英文:
React useEffect hook that depends on another useEffect
问题
I'll provide the translated code portion as requested:
我的NextJS 13项目中有一个组件,其中包含两个useEffect钩子,一个用于设置名为singleRecipe的React上下文状态数组变量,另一个我想要设置另一个名为ingredientsArr的局部状态变量。问题出现在首次渲染时,当我的代码到达第二个useEffect时,我收到了未定义的singleRecipe状态变量。一旦singleRecipe被定义,我该如何将ingredientsArr变量更新为singleRecipe中的一个元素?
useEffect(() => {
setSingleRecipe(recipes.find(({id}) => id === Number(recipeID)))
})
useEffect(() => {
setIngredientsArr(JSON.parse(singleRecipe.ingredients))
}, [singleRecipe])
* singleRecipe存储在上下文状态中,ingredientsArr是这个组件的局部变量
英文:
A component in my NextJS 13 project has two useEffect hooks, one that sets a React Context state array variable called singleRecipe, and another that I would like to set another local state variable called ingredientsArr. The issue arises on first render, I am receiving undefined for the singleRecipe state variable when my code reaches the second useEffect. How would I go about updating the ingredientsArr variable to an element from the singleRecipe only once singleRecipe is defined?
useEffect(() => {
setSingleRecipe(recipes.find(({id}) => id === Number(recipeID)))
})
useEffect(() => {
setIngredientsArr(JSON.parse(singleRecipe.ingredients))
}, [singleRecipe])
- singleRecipe is stored in context state and ingredientsArr is local to this component
答案1
得分: 2
Sure, here are the translations of the code-related content:
> I am receiving undefined for the singleRecipe state variable
我得到了未定义的单一食谱状态变量。
You can check if the value is undefined
before trying to use it. For example:
在尝试使用它之前,您可以检查该值是否为 undefined
。例如:
useEffect(() => {
if (singleRecipe) {
setIngredientsArr(JSON.parse(singleRecipe.ingredients))
}
}, [singleRecipe])
或者可以使用可选链,并在整体值为“falsy”时有条件地设置为空数组:
或者,如果目标是在一个整体效果中执行这两个操作,只需使用一个useEffect
调用:
useEffect(() => {
setIngredientsArr(JSON.parse(singleRecipe?.ingredients ?? '[]'))
}, [singleRecipe])
或者,如果目标是在一个整体效果中执行这两个操作,只需使用一个useEffect
调用:
useEffect(() => {
const newRecipe = recipes.find(({ id }) => id === Number(recipeID));
setSingleRecipe(newRecipe);
setIngredientsArr(JSON.parse(newRecipe.ingredients));
});
It's worth noting, if only for future readers... This effect will run on every render. Which is probably not what you want. Especially if the effect updates state, which triggers another render.
值得注意的是,仅供将来的读者参考... 这个效果将在每次渲染时运行。这可能不是您想要的。特别是如果效果更新状态,这会触发另一个渲染。
You can modify this effect to only run on the first render by providing an empty dependency array:
您可以通过提供一个空的依赖数组来修改此效果,以便仅在第一次渲染时运行:
useEffect(() => {
const newRecipe = recipes.find(({ id }) => id === Number(recipeID));
setSingleRecipe(newRecipe);
setIngredientsArr(JSON.parse(newRecipe.ingredients));
}, []); // <--- here
或者只在recipeID
更改时运行:
或者只在recipeID
更改时运行:
useEffect(() => {
const newRecipe = recipes.find(({ id }) => id === Number(recipeID));
setSingleRecipe(newRecipe);
setIngredientsArr(JSON.parse(newRecipe.ingredients));
}, [recipeID]); // <--- here
英文:
> I am receiving undefined for the singleRecipe state variable
You can check if the value is undefined
before trying to use it. For example:
useEffect(() => {
if (singleRecipe) {
setIngredientsArr(JSON.parse(singleRecipe.ingredients))
}
}, [singleRecipe])
Or perhaps use optional chaining and conditionally set to a blank array if the overall value is "falsy":
useEffect(() => {
setIngredientsArr(JSON.parse(singleRecipe?.ingredients ?? '[]'))
}, [singleRecipe])
Alternatively, if the goal is to perform both of these operations in one overall effect then just use one call to useEffect
:
useEffect(() => {
const newRecipe = recipes.find(({id}) => id === Number(recipeID));
setSingleRecipe(newRecipe);
setIngredientsArr(JSON.parse(newRecipe.ingredients));
});
It's worth noting, if only for future readers... This effect will run on every render. Which is probably not what you want. Especially if the effect updates state, which triggers another render.
You can modify this effect to only run on the first render by providing an empty dependency array:
useEffect(() => {
const newRecipe = recipes.find(({id}) => id === Number(recipeID));
setSingleRecipe(newRecipe);
setIngredientsArr(JSON.parse(newRecipe.ingredients));
}, []); // <--- here
Or to run only when recipeID
changes:
useEffect(() => {
const newRecipe = recipes.find(({id}) => id === Number(recipeID));
setSingleRecipe(newRecipe);
setIngredientsArr(JSON.parse(newRecipe.ingredients));
}, [recipeID]); // <--- here
答案2
得分: 1
你这里实际上不需要两个 useEffect:
useEffect(() => {
const myRecipe = recipes.find(({id}) => id === Number(recipeID));
setSingleRecipe(myRecipe);
setIngredientsArr(JSON.parse(myRecipe.ingredients));
}, []); // 空的依赖数组,只在第一次渲染后运行一次
注意,在你的代码中,第一个 `useEffect` 没有依赖数组,因此会在每次组件渲染时运行。
英文:
you don't really need two useEffect here:
useEffect(() => {
const myRecipe = recipes.find(({id}) => id === Number(recipeID));
setSingleRecipe(myRecipe);
setIngredientsArr(JSON.parse(myRecipe.ingredients));
}, []); // empty dependency array to run onlu once after the first render
Note that in your code the first useEffect
will run on each component render because it does not have a dependency array.
答案3
得分: 0
可以通过在第二个 useEffect 中添加一个检查来实现这一点:
useEffect(() => {
setSingleRecipe(recipes.find(({ id }) => id === Number(recipeID)))
})
useEffect(() => {
if (!singleRecipe) return;
setIngredientsArr(JSON.parse(singleRecipe.ingredients))
}, [singleRecipe])
虽然第一个 useEffect
没有依赖项似乎很奇怪。recipeId
是什么?如果它是一个 prop 或者 state 变量,你可能应该将它包含在依赖数组中:
useEffect(() => {
setSingleRecipe(recipes.find(({ id }) => id === Number(recipeID)))
}, [recipeId])
如果不将其包含在依赖数组中,它将在每次渲染时设置,这并不理想。
它为什么未定义是因为你在第一个 useEffect
中设置它,状态更新是异步的(因此新值在下一次渲染之前不可用)。
英文:
I think you can achieve this by adding a check to the second use effect:
useEffect(() => {
setSingleRecipe(recipes.find(({id}) => id === Number(recipeID)))
})
useEffect(() => {
if(!singleRecipe) return;
setIngredientsArr(JSON.parse(singleRecipe.ingredients))
}, [singleRecipe])
Although it seems strange that the first useEffect
has no dependencies. What is recipeId
? If that is a prop/state var you should probably include it in the dep array:
useEffect(() => {
setSingleRecipe(recipes.find(({id}) => id === Number(recipeID)))
}, [recipeId])
If you don't include it in the dep array, it will set it on every render which isn't ideal.
The reason it's undefined is you are setting it in the first useEffect
and state updates asynchronously (so the new value isn't available until the next render).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论