我是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])
});
但这也不起作用。
答案 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;