useState 变量不是删除函数中的最新版本,React
Posted
技术标签:
【中文标题】useState 变量不是删除函数中的最新版本,React【英文标题】:useState variable not latest version in delete function, React 【发布时间】:2020-06-24 18:18:22 【问题描述】:我有一个包含问题字段的 div 列表。对于每个按钮单击,我都会添加一行新的问题字段,并在状态中记住整个列表以及有多少行。我尝试添加一个删除按钮,但是当我的删除功能时,状态变量的值似乎是从创建行时记住的。我该如何解决这个问题,以便我可以访问 HandleDelete 函数中的完整列表?
const OefeningAanvragenDagboek = () =>
const t, i18n = useTranslation()
const [questionCount, setQuestionCount] = useState(1)
const [questionList, setQuestionList] = useState([])
const createNewLine = () =>
var newLine=
<div>
<Field type="text" name="vraag" + questionCount/>
<Field component="select" name="antwoordMogelijkheid"+questionCount>
<option value="">...</option>
<option value="open">t('oefeningAanvragenDagboek.open')</option>
<option value="schaal">t('oefeningAanvragenDagboek.scale')</option>
</Field>
<Field type="text" name="type"+questionCount/>
<button onClick=() => HandleDelete(questionCount-1)>t('assignmentCard.delete')</button>
</div>
setQuestionList(questionList => [...questionList, newLine])
setQuestionCount(questionCount+1)
const HandleDelete = (index)=>
console.log(questionList)
// setQuestionList(questionList.splice(index, 1))
return (
<div>
<button onClick=createNewLine>t('oefeningAanvragenDagboek.addQuestion')</button>
questionList
</div>
)
【问题讨论】:
splice
改变原始数组并返回删除的项目。你永远不应该改变状态。您的突变可能会被覆盖,我怀疑您是否想将其更新为仅包含已删除的值。
我也遇到了同样的问题,有解决办法吗?
下面的答案是这个@BryceSnyder 的解决方案。您能否通过codesandbox.io 或类似方式附上您的问题的最小示例?
@95faf8e76605e973 把它放在一起。codesandbox.io/s/charming-architecture-9kp71?file=/src/App.js 如果你在添加 toasts 后点击任一关闭,它只会爆炸列表。试图从下面做“答案”,但它只是进一步中断。
@95faf8e76605e973 我忘了我正在重构,添加了 ID。如果您单击 X,它会起作用,但如果您单击按钮,它不会并且很不稳定。这就是问题所在。如果您单击 5x,然后单击您创建的第一个,则整个列表将被删除。如果您点击 5x,然后点击刚刚创建的实例,您将获得所需的功能...
【参考方案1】:
使用functional setState
,因为HandleDelete
在questionList
上已关闭
setQuestionList(questionList => questionList.splice(index, 1))
setState() 上课updater 函数接收到的 state 和 props 都保证是最新的。
【讨论】:
splice
改变原始数组并返回删除的项目。这违反了反应的规则,也可能不会做他们想做的事。
是的,忘记了,需要修复答案并返回一个副本【参考方案2】:
主要解决issue on the OP's comments section,在撰写本文时,除了问题之外还获得了赏金。
有问题的沙盒:https://codesandbox.io/s/charming-architecture-9kp71?file=/src/App.js
基本上解决这个问题的方法就是对回调函数的参数进行所有的操作。对于我上面链接的沙盒问题,如果您查看下面代码中的removeToast
,则正在对list
数组进行操作。
有问题的代码:
export default function App()
const [list, setList] = useState([]);
const removeToast = (id) =>
const newList = list.filter(( toastId ) => toastId !== id);
setList([...newList]);
;
const addToast = () =>
const toastId = Math.random().toString(36).substr(2, 9);
const newList = [
...list,
toastId,
content: (
<>
<button onClick=() => removeToast(toastId)>Hi there</button>
Hello toastId
</>
)
];
setList([...newList]);
;
return (
<>
<button onClick=addToast>Show Toast</button>
<Toaster removeToast=removeToast toastList=list />
</>
);
然而,由于removeToast
对list
有一个闭包,我们需要对之前的状态进行过滤,该状态同样可以通过 setState 回调的第一个参数访问
修复:
const removeToast = (id) =>
setList((prev) =>
return prev.filter(( toastId ) => toastId !== id);
);
;
解决方案:https://codesandbox.io/s/suspicious-silence-r1n41?file=/src/App.js
【讨论】:
感谢您的及时帮助,不胜感激!我走了大约 90% 的路。不幸的是,我忘记在返回时添加数组传播:| 没有必要传播过滤结果,因为filter
已经创建了一个新数组。 IE。 setList((prev) => prev.filter(( toastId ) => toastId !== id));
【参考方案3】:
您可以将事件处理程序从容器传递给子项,然后从客户端调用事件处理程序。
例如,假设我有一个显示项目列表的应用,每个项目都有一个删除按钮,可以将它们从列表中删除。在这种情况下,父组件将提供项目列表和事件处理程序给子组件,然后子组件将负责渲染和调用事件处理程序。
看看我正在粘贴以下代码的codesandbox:
import React, useState from "react";
import "./styles.css";
export function List(props)
return (
<div>
props.items.map((i, idx) => (
<div class="item" key=idx>
i <span onClick=() => props.onDelete(idx)>X</span>
</div>
))
</div>
);
export default function App()
const [items, setItems] = useState([
"Item 1",
"Item 2",
"Item 3",
"Item 4",
"Item 5",
"Item 6"
]);
const deleteItem = (index) =>
if (index >= 0 && index < items.length)
const newItems = items.slice();
newItems.splice(index, 1);
setItems(newItems);
;
return (
<div className="App">
<List items=items onDelete=deleteItem></List>
</div>
);
【讨论】:
以上是关于useState 变量不是删除函数中的最新版本,React的主要内容,如果未能解决你的问题,请参考以下文章