简体   繁体   中英

React - Passing state as props not causing re-render on child component

I have a parent component that initiates state and then once mounted updates it from the results of a get request

const [vehicles, handleVehicles] = useState([])

    useEffect(() => {
        const token = localStorage.getItem('token')
        axios({
            //get data from backend
        }).then(({data}) => {
            handleVehicles(prevState => [...prevState, data])
        }).catch((err) => console.log(err))
    }, [])

I have the state passed down as a prop into a child component. In my child component I run a check to see if the vehicles array is populated...if it is I return some jsx otherwise I return nothing. My issue is that the state change won't reflect in the prop passed down and cause a re-render. It remains at an empty array unless I refresh the page.

I pass it down via

<RenderTableData vehicles={vehicles} />

My child component is:

const RenderTableData = (props) => {

    if (!props.vehicles[0]) {
        return null
    } else {
        return (
            props.vehicles[0].map((vehicle) => {
                return (
                    <tr key={vehicle._id}>
                        <td>{vehicle.name}</td>
                        <td>{vehicle._id}</td>
                        <td><button className="has-background-warning">Edit</button></td>
                        <td><button className="has-background-danger">Remove</button></td>
                    </tr>
                )
            })
        )
    }
}

How would I approach solving this?

Edit - It does actually work as is...For some reason the http request takes an age to return the data (and I was never patient enough to notice)...So I have a new problem now:(

I don't know what exactly is prevState but I think your problem is caused by passing to handleVehicles a function instead of the new value. So your code should be:

    const [vehicles, handleVehicles] = useState([])

    useEffect(() => {
        const token = localStorage.getItem('token')
        axios({
            //get data from backend
        }).then(({data}) => {
            handleVehicles([...prevState, data])
        }).catch((err) => console.log(err))
    }, [])

Why you are using the map function on the object. Your child component should be like below:

const RenderTableData = (props) => {

if (!props.vehicles[0]) {
    return null
} else {
    return (
        props.vehicles.map((vehicle) => {
            return (
                <tr key={vehicle._id}>
                    <td>{vehicle.name}</td>
                    <td>{vehicle._id}</td>
                    <td><button className="has-background-warning">Edit</button></td>
                    <td><button className="has-background-danger">Remove</button></td>
                </tr>
            )
        })
    )
}

}

I wrote a working example at CodeSandbox . Some comments:

Your effect will run just once, after the component mounts. If the API returns successfully, a new vehicle list is created with the previous one. But prevState is empty, so this is the same as handleVehicles(data) in this case. If you wanna spread data inside the vehicle list, don't forget to handleVehicles(prevState => [...prevState, ...data ]);

useEffect(() => {
    const token = localStorage.getItem('token')
    axios({
        //get data from backend
    }).then(({data}) => {
        handleVehicles(prevState => [...prevState, data])
    }).catch((err) => console.log(err))
}, [])

In your children component, you probably want to map over the vehicles list, not over the first element. So, you should remove the [0] in

const RenderTableData = (props) => {
    if (!props.vehicles[0]) {
        return null
    } else {
        return (
            props.vehicles[0].map((vehicle) => {
                return (
                    ...
                )
            })
        )
    }
}

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