反应DOM不更新状态变化

时间:2020-05-15 18:25:29

标签: javascript reactjs react-hooks codesandbox

我有一个react组件,可以接受任意数量的文件,每个文件都有自己的语言。我希望能够有一个按钮,使用户可以根据需要添加任意数量的文件,每个文件都有自己的语言下拉菜单。隔离问题后,我现在已经取消了文件上传。

我已经毫无问题地创建了许多类似的组件,但是由于某种原因,我在使用该组件时遇到了很大的麻烦。当我在下拉菜单中更改语言时,我会控制日志状态并看到该语言的状态已更新,但在map方法中的DOM上却未更新。

这是我的代码

function App() {
  const [files, setFiles] = useState([]);

  const languages = ["English", "Spanish", "Arabic", "French"];

  const handleAddFile = e => {
    let newFiles = files;
    newFiles.push({
      content: null,
      preview: null,
      language: ""
    });
    setFiles(newFiles);
  };

  const changeLanguage = (event, index) => {
    let newFiles = files;
    newFiles[index].language = event.target.value;
    setFiles(newFiles);
  };

  console.log(files);

  return (
    <div>
      <p>Files</p>
      <p>Upload a file for as many languages as you have</p>
      {files.map((file, index) => (
        <div key={index}>
          <p>current language: {file.language}</p>
          <select
            value={file.language}
            onChange={event => changeLanguage(event, index)}
          >
            <option value="" disabled>
              Select a language
            </option>
            {languages.map((lang, i) => (
              <option value={lang} key={i}>
                {lang}
              </option>
            ))}
          </select>
        </div>
      ))}
      <button onClick={e => handleAddFile(e)}>+ Add File</button>
    </div>
  );
}

我也制作了一个codeandbox来重现该问题,但实际上使事情变得更加复杂。当我在本地运行代码时,我可以添加文件实例,但是对于任何实例,select元素上的语言都不会在DOM上更新。在codesandbox中,除非我在编辑器中进行编辑,否则DOM上的任何内容都不会更新,然后一切都会按照我的期望进行更新,包括语言。在所有情况下,控制台记录的状态都与我期望的完全相同。沙盒中的组件与我本地的组件相同,尽管它在本地嵌入在另一个组件中。

https://codesandbox.io/s/ed4fx?file=/src/App.js:0-1248

1 个答案:

答案 0 :(得分:3)

方法handleAddFilechangeLanguage都存在问题,您直接访问状态值文件,因此要进行更新,您需要复制并进行更改并设置新值。 / p>

两种方法都需要进行的更新

let newFiles = files;

收件人

let newFiles = [...files];

正如@Brian建议的那样,当您在changeLanguage方法中更新深层嵌套的值(如语言)时。您可以执行如下所示的操作,以免改变状态。

const changeLanguage = (event, index) => {
  let newFiles = [...files];
  newFiles[index] = { ...newFiles[index], language: event.target.value };
  setFiles(newFiles);
};

检查此工作codesandbox

更好的解释here