useEffect 第一次打断 useState 数组

useEffect break array of useState at first time

我正在学习 React Hooks。我正在模拟数据 js 调用“MockFireBase.js”,如下所示:

const userIngredientsList = [];
export const Get = () => {
    return userIngredientsList;
}
export const Post = (ingredient) => {
    ingredient.id = userIngredientsList.length + 1;
    userIngredientsList.push(ingredient);
    return ingredient;
}

然后我的反应挂钩组件“Ingredients.js”将调用这个模拟实用程序,详情如下:

const Ingredients = () => {
  const [userIngredients, setUserIngredients] = useState([]);
  
  // only load one time
  useEffect(() => { setUserIngredients(Get()); }, []);
  
  const addIngredienHandler = ingredient => {
    let responsData = Post(ingredient);
    setUserIngredients(preIngredients => {
      return [...preIngredients, responsData]
    });
  }
  
  return (
    <div className="App">
      <IngredientForm onAddIngredient={addIngredienHandler} />
      <section>
        <IngredientList ingredients={userIngredients} />
      </section>
    </div>
  );
  )
} 

当我添加第一种成分时,它添加了两种(当然我在 console.log 中遇到了相同的关键问题)。然后我加了第二种成分就可以了。

如果我删除下面的 useEffect 代码,它会很好用。

// only load one time
useEffect(() => { setUserIngredients(loadedIngredients); }, []);

我想知道我在上面做错了什么,如果我使用 useEffect

问题不是在useEffect。这是关于改变全局 userIngredientsList 数组。

  1. 在 useEffect 中,您将初始组件状态设置为 userIngredientsList
  2. 然后在 addIngredienHandler 中调用 Post()。这个函数做了两件事: 2a.将新成分推送到全局 userIngredientsList array`。由于它与您在步骤 1 中保存在状态中的实例相同,因此您的状态现在已经包含此成分。 2a. Returns 这个成分
  3. 然后,addIngredienHandler 再次将此成分添加到状态中 - 所以您最终会在状态中使用它两次。

修复 1Post 函数中删除 userIngredientsList.push(ingredient); 行。

修复 2 或者,如果您需要这个全局成分列表以供进一步使用,您应该确保不要将它直接存储在您的组件状态中,而是在您的状态中创建一个浅表副本:

useEffect(() => { setUserIngredients([...Get()]); }, []);