为何在设置初始状态时运行useHook?

时间:2020-10-13 16:40:00

标签: javascript reactjs react-hooks

我有一个由useState()管理的数据:

const [data, setData] = useState() // undefined as the initial state

useEffect(() => {
  loadandSetData(setData) // some fetch then running setData to change data object
}, []);

useEffect(() => {
  console.log('Will request additional data...')
  console.log(data)
  loadSomeOtherData() // Should be executed only when data turns from undefined to something
}, [data]);

这个想法是从一个端点加载一些基本信息,然后从另一个端点加载一些其他数据,然后将它们组合在一起以供进一步使用。

我想在启动时运行第一个请求,仅在数据不是undefined时才运行下一个请求。 实际上,我看到console.log运行了两次-第一次运行时带有undefined值,第二次运行时加载了第一次useEffect调用。

这是正常行为还是我做错了什么?除了明确检查loadSomeOtherData()内部的内容之外,data对象中有什么内容时,如何确保loadSomeOtherData(data)运行打电话?

2 个答案:

答案 0 :(得分:0)

这是正常现象。即使第二个挂钩中的依赖项数组内部有data,也始终在装入后执行。

现在,您无需使用两个useEffect即可拥有所需的行为。您可以在useEffect中使用异步功能,并等待第一个数据完成,然后使用async...awaitPromise.then()(以您喜欢的为准)继续第二个数据

类似的东西:

const [data, setData] = useState() // undefined as the initial state
useEffect(async () => {
  const someData = await loadandSetData() // this returns a promise that resolves with the data retrieved (i.e a fetch()) - change name of variable
  // here you already have someData
  const someOtherData = await loadSomeOtherData(); // same as above
  // here you already have someOtherData
  
  setData([...someData, ...someOtherData]); // supposing both are array objects and you want to concat them using the spread operator
}, []);

答案 1 :(得分:0)

这是正常的行为,useEffect会在每个渲染(包括初始渲染)之后运行。但是,您应该更改useEffect的使用方式,以获取所需的行为。

useEffect(() => {
  
    if (data !== undefined) {
        // now the following will only execute when data is not undefined
        console.log('Will request additional data...')
        console.log(data)
        loadSomeOtherData()
    }
}, [data])

另一个选择是调用loadSomeOtherData的效果与loadAndSetData相同

useEffect(() => {
  // seems from the signature of how you used loadAndSetData that it takes a callback with a data object, so you could do this
  loadandSetData(data => {
      setData(data)
      loadSomeOtherData()
  }) 
}, []);