将数组设置为null,然后在useEffect React中进行更新

时间:2020-01-01 19:43:14

标签: javascript reactjs react-hooks

我是React的新手。我有一个MealList组件,将一组道具传递给该MealList组件,并根据该组件进行数据调用并更新一组膳食,这些膳食将显示在表格中。

const MealList = (props) => {
    const [meals, setMeals] = useState([]);

    useEffect(() => {

        const fetchMeals = async (userId, fromDate, toDate, fromTime, toTime) => {
            ...
            return resp;
        };
        fetchMeals(localStorage.getItem('user_id'), props.fromDate, props.toDate, props.fromTime, props.toTime).then(r => {
            setMeals([...meals, ...r.data])//The fetched data is stored in an array here.
        });
    }, [props]);
    console.log(props.fromDate);
    return (
        <div style={{width: '70%'}}>
            ...
            <Table striped bordered hover>
                <thead>
                <tr>
                    ...
                </tr>
                </thead>
                <tbody>
                {meals.map((meal, index) => (<Meal key={meal.id} count={index +1} meal={meal}/>))}//And displayed here
                </tbody>
            </Table>
        </div>

    )
};

我面临的问题是,每次通过道具更新MealList时,都会使用扩展语法setMeals([...meals, ...r.data])追加到现有列表中。

我的问题是如何将饭食数组设置为null,然后仅更新新值?我已经尝试过了:

fetchMeals(localStorage.getItem('user_id'), props.fromDate, props.toDate, props.fromTime, props.toTime).then(r => {
            setMeals([]);
            setMeals([...meals, ...r.data])
        });

但这也不起作用。

3 个答案:

答案 0 :(得分:2)

如果您希望获得与拼接效果相同的效果,则应使用

list = [
{
    'Status': 'Deleted',
    'Name': "My First Test"
},
{
    'Status': 'Modified',
    'Name': "My First Test"
}]

filterd_list = [l for l in list if l['Status'] == 'Modified']
print(filterd_list) # Only the modified one will be printed

否则会传递对 setMeals(r.data.slice()); 的引用,并且如果在r.data调用之后对该对象进行了更改,它可能会有所不同。

将数组传递给Javascript函数时,该函数不会收到该数组的副本,而是对您传递的原始对象的引用。例如:

setMeals

显然 let x = [1,2,3], y = null; function foo(xx) { y = xx; } foo(x); console.log(y); // gives [1, 2, 3] x[1] = 99; console.log(y); // gives [1, 99, 3] 中的代码(我们看不到)重用 fetchMeals数组,如果不进行复制,则会产生问题。我可能会将其归类为r.data中的(设计)错误,因为给定了我希望获得新接口而不是必须复制的重用接口的接口。

请注意

fetchMeals

相同
x.slice()

答案 1 :(得分:2)

以下是一个示例(试图模仿您的代码):

Stackblitz演示:https://stackblitz.com/edit/react-hooks-usestate-svnmpn?file=MealList.js

问题在于数据突变,如果要新的更改重新呈现组件并应用更新,则必须保持不变。

  const MealList = props => {
  const [meals, setMeals] = useState([]);

  useEffect(() => {
    const fetchMeals = async (userId, fromDate, toDate, fromTime, toTime) => {
      return await new Promise(res =>
        setTimeout(
          _ =>
            res({
              data: [
                { id: 1, name: "sphagetti" },
                { id: 2, name: "salad" },
                { id: 3, name: "soup" },
                { id: 4, name: "bacon and eggs" }
              ]
            }),
          2000
        )
      );
    };
    fetchMeals(1, "date1", "date2", "time", "time2").then(r =>
      setMeals([...r.data])
    );
  }, [props]);

  return (
    <div style={{ width: "70%" }}>
      {!meals.length && <p>wait 2 seconds...</p>}
      {meals.map((meal, index) => (
        <div key={meal.id} count={index + 1} meal={meal}>
          {meal.id + ". " + meal.name}
        </div>
      ))}
    </div>
  );
};

答案 2 :(得分:1)

可以请您尝试这种方法吗?我相信,减速器比简单的状态更改更适合您的需求。请记住,这是简单的示例。您可以将道具移至动作中并在另一个文件中进行提取,以保持组件的清洁并分离问题。

您还可以在此处运行代码段: https://codesandbox.io/s/fragrant-frog-y2e6j?fontsize=14&hidenavigation=1&theme=dark

import React, { useEffect, useReducer } from "react";

const mealsReducer = ({ meals }, action) => {
  switch (action.type) {
    case "ADD_MEALS": {
      return {
        meals: action.meals
      };
    }
    // no default
  }
};
const MealList = ({ fromDate, toDate, fromTime, toTime }) => {
  const [state, dispatch] = useReducer(mealsReducer, { meals: [] });

  useEffect(() => {
    const fetchMeals = (userId, fromDate, toDate, fromTime, toTime) => {
      return Promise.resolve({
        data: [{ id: Math.floor(Math.random() * 100), name: "blabla" }]
      });
    };
    fetchMeals(0, fromDate, toDate, fromTime, toTime).then(({ data }) =>
      dispatch({ type: "ADD_MEALS", meals: data })
    );
  }, [fromDate, toDate, fromTime, toTime]);

  return (
    <ul>
      {state.meals.map((meal, index) => (
        <li key={meal.id}>{ meal.name }</li>
      ))}
    </ul>
  );
};

export default MealList;