First new to ReactJS so bear with me. I have an app that I am attempting to sync using an external api. The structure looks something like
APP ----> NAVBAR ---->MENU
| |->AVATAR
|
->MAIN -> HOME
|->PROFILE --->PROFILE
|->LOGINHANDLER
The loginhandler authenticates with the api server and obtains credentials which the profile compenent then uses to call an update and retrieve the users profile from the api server. The NAVBAR has the AVATAR which uses an image retrieved from the profile.
If the profile updater gets an updated image I need to trigger state update in the navbar to use the new profile image
function App() {
const loggedIn = (localStorage.getItem('wp_user') !== null);
const [seed,setSeed] = useState(0)
const update =()=>{
setSeed(Math.random);
}
return (
<div className="App">
<Navigation auth={loggedIn} />
<Main onChange={update}/>
</div>
);
}
I know that using this is rerendering the whole app…which is not ideal.
Anyway I then pass the function down through each compontent via props until I hit the Profile component
export default function Profile(onChange){
const [name,setName] = useState(getUserName())
const [email,setEmail] =useState('');
const [link,setLink] =useState('');
useEffect(() => {
new Api().getProfile().then(res=>{
let update = false;
if(res === null || res === undefined){
} else {
if (res.hasOwnProperty('name')) {
if (res['name'] !== name){
setName(res['name']);
}
}
if(res.hasOwnProperty('first_name')){
let fName = res['first_name'];
let sName = res['last_name'];
let updated = fName + " "+ sName;
if(updated !== name){
setName(updated);
}
}
if (res.hasOwnProperty('email')) {
if (res['email'] !== email){
setEmail(res['email']);
}
}
if (res.hasOwnProperty('link')) {
if (res['link'] !== link){
setLink(res['link']);
}
}
if (res.hasOwnProperty('avatar_urls')) {
if(getProfileUrl() !== res.avatar_urls['96']) {
setProfileUrl(res.avatar_urls['96'])
update = true;
}
}
if(update){
onChange();
}
}
});
}, [onChange]);
return (
<Card>
<Typography component='a' href={link} >
Name: {name}
</Typography>
<Typography>
Email: {email}
</Typography>
</Card>
)
}
I have used profile like
function UserWindow(onChange){
return (
<div>
<header className="Login-Header">
<h1>Profile</h1>
</header>
<Profile onChange={onChange}/>
<AuthenticatorForm/>
</div>
);
}
and the Main window looks like
const Main = ({onChange}) => {
return (
<div className="App">
<Routes>
<Route path='/' element={<Home/>}></Route>
<Route path='/User' element={<UserWindow onChange={onChange} />}></Route>
</Routes>
</div>
)}
I am getting the error…
ERROR onChange is not a function TypeError: onChange is not a function
[![enter image description here][1]][1]
[1]: https://i.stack.imgur.com/1L9r9.png
What is my mistake?
>Solution :
You need to de-structure the props in your UserWindow component like you did in Main. The parameter you define when you create a function component is the props object, so by saying {onChange} you are basically getting the onChange prop from the props object in a new variable.
If you instead just use onChange, you are basically naming your props object onChange. Here is a solution:
function UserWindow({onChange}){ // <-- here
return (
<div>
<header className="Login-Header">
<h1>Profile</h1>
</header>
<Profile onChange={onChange}/>
<AuthenticatorForm/>
</div>
);
}