反应-通过状态传递道具而不导致子组件重新渲染

时间:2020-07-15 14:00:55

标签: reactjs

我有一个初始化状态的父组件,然后在装入后根据获取请求的结果对其进行更新

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))
    }, [])

我将状态作为道具传递给子组件。在我的子组件中,我运行检查以查看是否填充了Vehicles数组...如果是,则返回一些jsx,否则不返回任何内容。我的问题是状态更改不会反映在传递的道具中并导致重新渲染。除非刷新页面,否则它将保持为空数组。

我通过

<RenderTableData vehicles={vehicles} />

我的子组件是:

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>
                )
            })
        )
    }
}

我将如何解决这个问题?

编辑-实际上,它确实可以工作...由于某种原因,http请求花了一定的时间才能返回数据(而且我从没有耐心地注意到)...所以我有现在有一个新问题:(

3 个答案:

答案 0 :(得分:0)

我不知道prevState到底是什么,但是我认为您的问题是由传递给handleVehicles的函数而不是新值引起的。因此您的代码应为:

    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))
    }, [])

答案 1 :(得分:0)

为什么要在对象上使用map函数。您的子组件应如下所示:

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>
            )
        })
    )
}

}

答案 2 :(得分:0)

我在CodeSandbox上写了一个工作示例。一些评论:

在组件安装后,您的效果将只运行一次。 如果API成功返回,则会使用前一个创建新的车辆清单。但是prevState为空,因此在这种情况下与handleVehicles(data)相同。如果您想在车辆列表中传播数据,请不要忘记handleVehicles(prevState => [...prevState, ...数据 ]);

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

在子组件中,您可能希望映射到车辆列表,而不是第一个元素。因此,您应该删除{p中的[0]

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