Home > Back-end >  REACT JS - Passing values from one component to another
REACT JS - Passing values from one component to another

Time:07-26

I have a NavBar.js component thats holds login info on the logged in user. When the user is logged in it says "Welcome" along with the user details. I want to implement the same function in ProductList.js component so when a user posts a blog, it says "Posted By: " along with the users log in details. How would I pass the details form NavBar.js to ProductList.js ?

import React, { useState, useEffect } from 'react';
import { NavLink } from 'react-router-dom';


const NavBar = (props) => {
  const providers = ['twitter', 'github', 'aad'];
  const redirect = window.location.pathname;
  const [userInfo, setUserInfo] = useState();

  useEffect(() => {
    (async () => {
      setUserInfo(await getUserInfo());
    })();
  }, []);

  async function getUserInfo() {
    try {
      const response = await fetch('/.auth/me');
      const payload = await response.json();
      const { clientPrincipal } = payload;
      return clientPrincipal;
    } catch (error) {
      console.error('No profile could be found');
      return undefined;
    }
  }

  return (
    <div className="column is-2">
      <nav className="menu">
        <p className="menu-label">Menu</p>
        <ul className="menu-list">
          <NavLink to="/products" activeClassName="active-link">
            Recipes 
          </NavLink>
          <NavLink to="/about" activeClassName="active-link">
            Help
          </NavLink>
        </ul>
        {props.children}
      </nav>
      <nav className="menu auth">
        <p className="menu-label">LOGIN</p>
        <div className="menu-list auth">
          {!userInfo &&
            providers.map((provider) => (
              <a key={provider} href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}>
                {provider}
              </a>
            ))}
          {userInfo && <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>Logout</a>}
        </div>
      </nav>
      {userInfo && (
        <div>
          <div className="user">
            <p>Welcome</p>
            <p>{userInfo && userInfo.userDetails}</p>
            <p>{userInfo && userInfo.identityProvider}</p>
          </div>
        </div>
      )}
    </div>
  );
};

export default NavBar;

This is a snippet from ProductsList.js, where I want the user details data to be passed to:

<footer className="card-footer ">
    <ButtonFooter
      className="cancel-button"
      iconClasses="fas fa-undo"
      onClick={handleCancelProduct}
      label="Cancel"
    />
    <ButtonFooter
      className="save-button"
      iconClasses="fas fa-save"
      onClick={handleSave}
      label="Save"
    /> Posted By: {}
  </footer>

CodePudding user response:

You have to use a global state manager like redux , Recoil , context-api etc. If the state receiver component is not a child component of state sender component, you can't use props. You may check Redux official documentation.

CodePudding user response:

You can probably force your current set up to work using an event emitter, where your ProductList sends out an event requesting the user info, and the NavBar is listening for those events, and responds with the appropriate data.

I don't recommend this, though, with your current set up.

I recommend lifing your user info logic out of the NavBar and into app state that sits above both your NavBar and your ProductList in the component tree. The idea is that you'll have a store of app state data that sits near the root level of your app, to hold things that multiple parts of your app may want access to at different moments. In this case, your NavBar and your ProductList both care about user data.

This also allows the NavBar component focus on generating HTML rather than data fetching and storing. Separating these concerns assists greatly with your app growing over time (maybe you create another component down the road that also wants to know about User info), and then also things like testing so that you don't have to have a mock API in place to see if your NavBar is displaying the data it expects correctly.

What I'm suggesting will pay off in the end, but it does increase the complexity of what you're doing. You'll have to rearchitect a few pieces of your app to put a centralized data store in place. And create ways to add data to that store (a user logs in) and get data out of the store (components want to display user info).

There are several popular ways to handle this sort of app state store.

  • Redux taught me a lot about how to organize data flows and has a library react-redux to integrate directly with your React components
  • React has Context Provider and useContext hook, and even has a useReducer hook that allows you to re-create Redux using native React tools
  • RxJS I have not used personally, but it offers some benefits that the others do not.
  • There are many more. Google "React state libraries" to explore your options

I know this doesn't directly answer your question, but I hope it helps a bit nonetheless.

  • Related