开发者问题收集

useState 变量不是删除函数中的最新版本,React

2020-03-12
538

我有一个包含问题字段的 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>
  )
}
3个回答

使用 功能性 setState ,因为 HandleDeletequestionList 上有闭包

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

Both state and props received by the updater function are guaranteed to be up-to-date.

Dennis Vash
2020-03-12

您可以将事件处理程序从容器传递给子组件,然后从客户端 调用 事件处理程序。

例如,假设我有一个显示项目列表的应用程序,每个项目都有一个删除按钮,用于将其从列表中删除。在这种情况下,父组件将向子组件提供 项目列表 事件处理程序 ,然后子组件将负责 渲染 调用事件处理程序

查看此 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>
  );
}

Dipen Shah
2020-10-06

主要解决 OP 评论部分的问题 ,在撰写本文时,除了问题之外还获得了赏金。

存在问题的 SandBox: 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

95faf8e76605e973
2020-10-06