Home > Enterprise >  How to pass a function from Parent to an element within a route in React.js?
How to pass a function from Parent to an element within a route in React.js?

Time:05-14

I want to pass a function to a component through a Route , I can do it with direct children but when it comes to Routes i can't figure it how to do it.

look at the code below , i want to pass "updateUserState" function to Profile Component , the function works properly in Header component but it's not working in Profile component which lives inside the Routes .

class App extends React.Component {  

  updateUserState = (currentUser) => {
    if(currentUser != null) {
      this.setState({
        currentUser: currentUser
      })
    } else {
      this.setState({
        currentUser: null
      });
    }
    return this.state.currentUser;
  }
  
  render() {
    return (
      <div className="App">
        <Header updateUserState={this.updateUserState} />
        <Routes>
          <Route path='/profile' element={<ProfilePage updateUserState={this.updateUserState} />}/>
        </Routes>
      </div>  
    );
  }
}

this is the code in Profile component which is completely similar to Header Component :

const ProfileCard = ({updateUserState}) => {  
   const signout = () => {
      handleLogout()
      updateUserState()
   }
   return (
      <div className='profile-card'>
         <a onClick={() => signout()}>
            Sign Out 
         </a>  
      </div>
   )
}

Update : solved thanks to Abir Taheer !

class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      currentUser: null
    }  

    this.updateUserState = this.updateUserState.bind(this);
  }


  updateUserState = (currentUser) => {
    if(currentUser != null) {
      this.setState({
        currentUser: currentUser
      }, () => console.log(this.state.currentUser))
    } else {
      this.setState({
        currentUser: null
      }, () => console.log(this.state.currentUser));
    }
    return this.state.currentUser;
  }
  
  render() {
    return (
      <div className="App">
  
        <Header currentUser={this.state.currentUser} updateUserState={this.updateUserState} />
        <Routes>
          <Route path='/profile' element={<ProfilePage updateUserState={this.updateUserState}
          currentUser={this.state.currentUser} />}
          />
        </Routes>

        
      </div>  
    );
  }
}

then inside ProfilePage :


const ProfilePage = ( {currentUser, updateUserState} ) => {
   return (
      <div>{
            currentUser ? 
            <div>
               <ProfileCard id={currentUser.id} updateUserState={updateUserState} />
            </div>
            :
            <h1>No User Signed In</h1>
      }</div>
   )
}

And ProfileCard :

const ProfileCard = ({id, updateUserState}) => {
   
   const signout = () => {
      handleLogout()
      updateUserState();
   }

   return (
      <div className='profile-card'>
         <a onClick={() => signout()}>
            Sign Out 
         </a>  
      </div>
   )
}

CodePudding user response:

The issue arises because of the this keyword. When you're passing a function to another component you need to bind the this keyword to the parent instance otherwise it may not work properly.

This behavior is described in the React Docs here: https://reactjs.org/docs/faq-functions.html

and more specifically further down in the page here: Why is binding necessary at all?

When you bind this to the parent instance then it refers to the correct state and the function should work.

You need to update your component like such:

class App extends React.Component {
  constructor(props) {
    super(props);

    // Make sure to initialize your state accordingly
    this.state = {
      currentUser: null,
    };

    // --- This is the line you need ---
    this.updateUserState = this.updateUserState.bind(this);
  }

  updateUserState(currentUser) {
    if (currentUser != null) {
      this.setState({
        currentUser: currentUser,
      });
    } else {
      this.setState({
        currentUser: null,
      });
    }
    return this.state.currentUser;
  }

  render() {
    return (
      <div className="App">
        <Header updateUserState={this.updateUserState} />
        <Routes>
          <Route
            path="/profile"
            element={<ProfilePage updateUserState={this.updateUserState} />}
          />
        </Routes>
      </div>
    );
  }
}

CodePudding user response:

The way you do it seems like you are rendering the component instead of passing a reference.

How I would suggest is to wrap the component in another function and return with your function passed in as a prop. So basically making another react component with the method passed in. Use that wrapper component instead:

const wrappedProfilePage = () => <ProfilePage updateUserState={this.updateUserState} />;

..
.
.

 <Route path='/profile' element={wrappedProfilePage}/>


  • Related