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,因为HandleDeletequestionList 上已关闭

setQuestionList(questionList => questionList.splice(index, 1))

updater 函数接收到的 state 和 props 都保证是最新的。

setState() 上课

【讨论】:

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 />
    </>
  );

然而,由于removeToastlist 有一个闭包,我们需要对之前的状态进行过滤,该状态同样可以通过 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) =&gt; prev.filter(( toastId ) =&gt; 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的主要内容,如果未能解决你的问题,请参考以下文章

useReducer 和 useState

useState & useReducer

useState和useEffect

为啥回调中的 React useState 依赖项为空?

为啥R中的回归会删除因子变量的索引1? [复制]

计算并向R中的数据框添加新变量