简体   繁体   中英

Can't update parent state from child using functional components

I am having an issue with my React app. I am trying to set the state of the parent component based on the child component's value. I can see in the dev tools and log window that the child's value is being received by the parent; however, the setState is not working as it should. I have tried creating a separate function just to set the values; hoping for it to act as a middleware but no luck.

I have been through about a couple of StackOverflow threads but not many cater for functional components. I found the following codegrepper snippet for reference but it does not help either.

link: https://www.codegrepper.com/code-examples/javascript/react+function+component+state

Most of the threads deal with how to get the value to the parent component; however, my issue is more "setting the state" specific.

import React, { useEffect, useState } from "react";
import Character from "../component/Character";
import Filter from "../component/Filter";
import Pagination from "../component/Pagination";
import axios from "axios";
import "./Home.css";

const Home = (props) => {

    const [API, setAPI] = useState(`https://someapi.com/api/character/?gender=&status=&name=`);
    const [characterData, setCharacterData] = useState([]);
    const [pagination, setPagination] = useState(0);

    const makeNetworkRequest = (data) => {
        setAPI(data);
        setTimeout(() => {
            axios.get(data).then(resp => {
                setPagination(resp.data.info)
                setCharacterData(resp.data.results)
            })
        }, 1000)
    }

    const handleFormCallBack = (childData) => {
        setAPI(childData);
        makeNetworkRequest(API);
        console.log(`Parent handler data ${childData}`)
        console.log(`Parent handler API ${API}`)
    }
     
    useEffect(() => {
        makeNetworkRequest(API)
    }, [characterData.length]);


    const mappedCharacters = characterData.length > 0 ? characterData.map((character) => <Character key={character.id} id={character.id} alive={character.status} /* status={<DeadOrAlive deadoralive={character.status} /> }*/ gender={character.gender} name={character.name} image={character.image} />) : <h4>Loading...</h4>

    return (
        <div className="home-container">
            <h3>Home</h3>
            <Filter parentCallBack={handleFormCallBack} />
            <div className="characters-container">
                {mappedCharacters}
            </div>
            {/* <Pagination pages={pagination.pages}/> */}
        </div>
    )
}

export default Home;

In the code above I am using a callback function on the parent named "handleFormCallBack", mentioned again below to get the information from the child filter component. When I log the value, the following results are being generated.

const handleFormCallBack = (childData) => {
        setAPI(childData);
        makeNetworkRequest(API);

        console.log(`Parent handler data ${childData}`) 
        // Parent handler data https://someapi.com/api/character/?gender=&status=&name=charactername

        console.log(`Parent handler API ${API}`) 
        // Parent handler API https://someapi.com/api/character/?gender=&status=&name=

    }

I am not sure what I am doing wrong but any sort of help would be much appreciated.

Kind Regards

useState works pretty much like setState and it is not synchronous, so when you set the new value using setAPI(childData); react is still changing the state and before it actually does so both of your console.log() statements are being executed.

Solution - after setting the new value you need to track if it has changed, so use a useEffect hook for the endpoint url and then when it changes do what you want.

useEffect(() =< {
  // do anything you want to here when the API value changes. you can also add if conditions inside here.
}, [API])

Just to check what I have explained, after calling setAPI(childData); add a setTimeout like

setTimeout(() => { // you will get new values here. this is just to make my point clear

console.log( Parent handler data ${childData} )

console.log( Parent handler API ${API} )

}, 5000);

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