skip to Main Content

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?

2

Answers


  1. You’ve got a bunch of syntax errors to check through. hint there is to look at the props you’ve forgottne to destructure (onChange) => ({ onChange })

    But I would highly recommend learning about context providers for passing state around different components, your approach will get complicated quickly.

    old doc – https://legacy.reactjs.org/docs/context.html

    new doc – https://react.dev/reference/react/createContext

    Login or Signup to reply.
  2. 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>
        );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search