有父子两个组件 父子都有一个数组 父组件的数组list更新, 子组件的数组tableData会跟着更新,并显示在表格上.
现在有个新增的按钮, 要求在新增时 先更新一下表格 再插入新的一行. 但是更新表格是在父组件请求,子组件通过useEffect跟着更新,导致新增时插入的一行被覆盖了(useEffect更新的逻辑比插入逻辑晚导致被覆盖),要怎么处理.
// 父组件const Father = () => { const [list, setList] = useState([]) const getListData = async () => { // 请求获取list数据 const res = await getList().catch(() => {}) setList(res.data) } return (<Son list={list} getListData={getListData} />)}
// 子组件const Son = ({list, getListData}) => { const [tableData, setTableData] = useState([]) // 当父组件的数据更新时 子组件也跟着更新 useEffect(() => { setTableData(list) }, [list]) // 新增 const onAdd = async () => { // 在新增之前先获取一下最新的表格数据list 调用父组件的请求函数 因为useEffect 当前子组件的tableData也会更新一下 await getListData() // 给当前组件的表格数据添加一行新增的空行(不改变父组件的数据) 但是由于这里会先于useEffect执行 所以会被覆盖 没有效果 setTableData([{空行数据}, ...tableData]) } return ( <div> <Table dataSource={tableData} /> <Button onClick={onAdd}>新增</Button> </div> )}
一个办法是把新增一行的逻辑移到useEffect处,加上判断来执行. 但明显这么写很不友好.
Son 组件的 list 发生变化以后会 setTableData,导致覆盖了 onAdd 里已经 set 的值。
我们可以这么做,把 onAdd 的值单独放到一个 state 里,然后在渲染时结合 props 里的 list 属性计算 dataSource 的值
// 子组件const Son = ({list, getListData}) => { // const [tableData, setTableData] = useState([]) // 当父组件的数据更新时 子组件也跟着更新 // useEffect(() => { // setTableData(list) // }, [list]) const [newItem, setNewItem] = useState(); // 新增 const onAdd = async () => { // 在新增之前先获取一下最新的表格数据list 调用父组件的请求函数 因为useEffect 当前子组件的tableData也会更新一下 await getListData() setNewItem({空行数据}) } return ( <div> <Table dataSource={newItem ? [newItem,...list] : list} /> <Button onClick={onAdd}>新增</Button> </div> )}
const Son = ({list, getListData}) => { const [tableData, setTableData] = useState([]); const [isUpdating, setIsUpdating] = useState(false); useEffect(() => { if (isUpdating) { setTableData([空行数据, ...list]); setIsUpdating(false); // 重置状态 } else { setTableData(list); } }, [list]); const onAdd = async () => { setIsUpdating(true); await getListData(); } return ( <div> <Table dataSource={tableData} /> <Button onClick={onAdd}>新增</Button> </div> )}
这其实是一个组件设计上的问题,用于渲染的表格数据只需要有一份即可,通常作为根组件的 state 是没问题的。但你这里子组件又维护了一份 state,对于组件的渲染来说形成了一个双数据源,不仅容易造成你描述的这种问题,也无端增加了开发过程的心智负担。
正确的做法是 子组件
直接使用父组件传过来的 list 去渲染,不用再存一个 state,如果存在子组件需要更新父组件的 state 的情况,应该从父组件传一个用于更新的方法给子组件。
总之保证 渲染数据的单一性
以及 更新数据方式的唯一性
基本上就能避免这种问题的出现
比较简单的处理方式如下
// 父组件const Father = () => { const [list, setList] = useState([]) const getListData = async () => { // 请求获取list数据 const res = await getList().catch(() => {}) setList(res.data) } return (<Son list={list} setList={setList} getListData={getListData} />)}
// 子组件const Son = ({list, setList, getListData}) => { // 新增 const onAdd = async () => { await getListData() setList((prevList) => [{空行数据}, ...prevList]) } return ( <div> <Table dataSource={list} /> <Button onClick={onAdd}>新增</Button> </div> )}
你可以通过将更新表格数据的操作放在 useEffect
内部来解决这个问题。这样的话,当表格数据更新后,新增的行也会被正确显示出来。以下是你可以尝试的修改后的代码:
父组件代码不变:
// 父组件const Father = () => { const [list, setList] = useState([]); const getListData = async () => { // 请求获取list数据 const res = await getList().catch(() => {}); setList(res.data); }; return (<Son list={list} getListData={getListData} />);};
子组件的代码如下:
// 子组件const Son = ({list, getListData}) => { const [tableData, setTableData] = useState([]); // 当父组件的数据更新时 子组件也跟着更新 useEffect(() => { setTableData(list); }, [list]); // 新增 const onAdd = async () => { // 在新增之前先获取一下最新的表格数据list 调用父组件的请求函数 因为useEffect 当前子组件的tableData也会更新一下 await getListData(); }; useEffect(() => { // 在新增后,再次获取数据,并且插入新的空行 const newTableData = [...tableData, {空行数据}]; setTableData(newTableData); }, []); // 注意这里传入的是一个空数组,这样这个useEffect就只会在组件挂载和更新时执行,不会在onAdd点击时执行 return ( <div> <Table dataSource={tableData} /> <Button onClick={onAdd}>新增</Button> </div> );};
在这个修改后的代码中,新增的数据是通过 useEffect
插入的,而不是在 onAdd
函数中插入的。这样就保证了在 useEffect
更新表格数据后,新增的行会被正确显示出来。注意在 useEffect
中我们使用的是 [tableData]
,这样每次 tableData
更新时,useEffect
就会执行。在 useEffect
中我们获取新的数据并将新的空行添加进去,然后设置新的 tableData
。
请帮助理解ExecutorService#AwaitTermination(timeout)行为。 当我的代码中有: 在本例中,pool中的任务是否在同一线程中shutdownAndAwaitTermination()之后的任何其他调用之前完成? 看看在生产过程中发生的事情,我相信答案是否定的,但我只想了解如何确保在调用shutdownAndAwaitTermination()后放置的任何代码将在
问题内容: 我正在编写一个swing应用,当执行某些方法时,我希望有“ wait”光标。我们可以这样: 我想要实现的是一个Java批注,该批注将在方法执行之前设置等待游标,并在执行后将其设置回正常状态。所以前面的例子看起来像这样 我怎样才能做到这一点?也欢迎提出有关解决此问题的其他方法的建议。谢谢! PS-我们在项目中使用Google Guice,但我不知道如何使用它来解决问题。如果有人为我提供类
问题内容: 我想知道以下代码的行为背后的机制是什么: 我的理解是不 返回 函数,而是 关闭连接/结束请求 。这可以解释为什么我仍然可以在命令后执行代码(我查看了快速源,但它似乎不是异步函数)。 还有其他我可能会想念的东西吗? 问题答案: 当然可以结束HTTP响应,但是它对您的代码没有做任何特殊的事情。 即使您已结束回复,也可以继续做其他事情。 但是,您 无法 做的是利用进行任何有用的操作。由于响应
问题内容: ExpressJS中间件,,有像钩子和。 但是我正在寻找和方法的挂钩。 问题答案: 和中间件可用于“ 之前 ”,而and 事件的组合可用于“ 之后” 。 中间件就是一个例子,默认情况下,它将在响应后追加到日志中。 只需确保先使用此“ 中间件 ”即可,因为顺序很重要。
因为我们知道progressdialog需要一个参数上下文或获取片段的活动,但在解除对话框后,它转到了另一个片段,我将其设置为mainactivity默认片段为homepage 这是我课堂上使用的方法
我正在Java的Android应用程序中工作,其中调用类并在OnCreateView方法中进行测量。然而,一旦完成,我必须自动发送他的测量结果。但我不能。是否有继承自:java.lang.对象android.app.片段的方法,可以在OncreateView进程之后执行函数。因为目前数据已经发送,但还没有时间填充。 谢谢你的帮助