简体   繁体   中英

Child component does not get state from parent

I have the following code, in App.js;

constructor() {
    super();
    this.state = {
        isLoggedIn: false,
        username: "",
    }
}

componentDidMount() {
    let isLoggedIn = false;
    let username = "";

    if (localStorage.getItem("token")) {
        fetch("https://localhost:8000/user", {
            method: "POST",
            headers: {
                "Authorization": `Bearer ${localStorage.getItem("token")}`
            }
        }).then(response => response.json()).then(response => {
            if (response.success) {
                isLoggedIn = true;
                username = response.username;
            } else {
                isLoggedIn = false;
                username = "";
                localStorage.removeItem("token");
            }

            this.setState({
                isLoggedIn : isLoggedIn,
                username: username
            })
        })
    }
}

render() {

    return (
       <Navbar username={this.state.username}/>
    )
}

By console logging the output, once componentDidMount is called the username in state is assigned as it should be. In Navbar.js;

constructor(props) {
    super(props);
    this.state = {
        navComponents: []
    }
}

componentDidMount()  {
    console.log(this.props.username);
    let navComponents = [];
    if (this.props.username === "") { //Not Signed In.
        navComponents.push(
            <ul className="Navbar-list">
                <li className="Navbar-item">
                    <Link to="/register" className="Navbar-link">Sign Up</Link>
                </li>
                <li className="Navbar-item">
                    <Link to="/login" className="Navbar-link">Log In</Link>
                </li>
            </ul>
        );
    } else {
        navComponents.push(
            <p>Hello, {this.props.username}</p>
        )
        navComponents.push(
            <ul className="Navbar-item">
                <Link to="/signout" className="Navbar-link">Sign Out</Link>
            </ul>
        )
    }
    this.setState({
        navComponents : navComponents
    })
}

I believe it should be getting username from App. However, username is always an empty string(The initial state of App). I'm unsure as to why Navbar isn't updating once component is mounted in App.

Your doing it wrong, isn't ur render function suppose to do the markup for a component, try like this should work fine.

constructor(props) {
    super(props);
}



render(){
    return (
            {this.props.username ? 
             <> 
              <p>Hello, {this.props.username}</p>
              <ul className="Navbar-item">
                <Link to="/signout" className="Navbar-link">Sign Out</Link>
             </ul>
             </>
             : 
            <ul className="Navbar-list">
                <li className="Navbar-item">
                    <Link to="/register" className="Navbar-link">Sign Up</Link>
                </li>
                <li className="Navbar-item">
                    <Link to="/login" className="Navbar-link">Log In</Link>
                </li>
            </ul>})
}

The reason is very simple, because componentDidMount of Navbar only being fired once, before username has a value.

What's happening with the flow is as below

  1. App.js render being invoked
  2. App.js componentDidMount being invoked
  3. App.js fire API call
  4. Navbar render being invoked
  5. Navbar componentDidMount being invoked
  6. Result of Step 3 coming back

Now because componentDidMount of Navbar will only be fired once, hence you will always see this.props.username is empty there. One of the simplest solution is by to handle your logic at componentDidUpdate instead of componentDidMount

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM