reactjs React应用无法在for循环中设置useState变量

8yparm6h  于 2023-03-22  发布在  React
关注(0)|答案(3)|浏览(238)

我有以下React代码:

import { useState } from 'react';
import './App.css';
import Layout from './components/Layout';

interface WordsPayload {
  listedwords: string[]
}

function App() {
  const [word, setWord] = useState({
    wordValue: ""
  });
  const [words, setWords] = useState<string[]>([]);

  const handleWordChange = (event: { target: { name: any; value: any; }; }) => {
    setWord({ ...word, [event.target.name]: event.target.value });
  };

  const handleWordSubmit = (event: { preventDefault: () => void; }) => {
    event.preventDefault();
    setWords([...words, word.wordValue as string]);
    setWord({ wordValue: "" });
  };

  const handleSubmit = async (event: { preventDefault: () => void; }) => {
    event.preventDefault();
    const jsnWords: WordsPayload =
    {
      listedwords: words
    }
    const findAnagrams = await fetch('http://localhost:3000/findanagrams', {
      method: 'POST',
      headers: {'Content-Type':'application/json'},
      body: JSON.stringify(jsnWords)
    });
    const anagramsFound = await findAnagrams.json();
    console.log(anagramsFound);
    return findAnagrams;
  };

  return (
    <Layout>
      <section className="container">
        <div className="flex-1 space-y-4">
          <h1 className="text-4xl font-bold">
            Anagram Finder
          </h1>
          <p className="max-w-xl leading-relaxed">
            Type words consisting of only alphanumeric characters
            into the text box. When you finish a word click "Add"
            After you finish adding words click submit.
          </p>
          <div className="items-center justify-center">
          <button onClick={handleSubmit}>
            Submit
          </button>
          </div>
        </div>
        <form onSubmit={handleWordSubmit}>
          <div className="mb-6">
            <label className="block mb-2">Type word here</label>
            <input
              type="text"
              name="wordValue"
              placeholder="Name"
              value={word.wordValue}
              onChange={handleWordChange}
            />
          </div>
          <button type="submit" className="dark:focus:ring-blue-800">Add Word</button>
        </form>
      </section>
      <section className="container">
        <div className="flex-1 space-y-4"></div>
        {words.map(function(d, idx){
          return (<span key={idx}>{d}</span>)
        })}
      </section>
    </Layout>
  )
}

export default App

我有一个文本框,在按下按钮时,它将输入的单词推送到words中,这是一个useState数组。这是它在操作中的样子:

我修改了handleWordSubmit,允许一次向words useState数组添加几个单词,方法是在,值处分隔输入字符串,并一次推送所有这些数组值。
现在它看起来像这样:

const handleWordSubmit = (event: { preventDefault: () => void; }) => {
    event.preventDefault();
    if (word.wordValue.includes(',')) {
        const wordParsed = word.wordValue.split(',');
        for (const wordParsedIndividual in wordParsed) {
            const wordStrippedMulti = wordParsed[wordParsedIndividual].replace(/[^\w\s!?]/g, '');
            console.log(wordStrippedMulti);
            setWords([...words, wordStrippedMulti as string])
        }
    } else {
        const wordStrippedSingle = word.wordValue.replace(/[^\w\s!?]/g, '');
        setWords([...words, wordStrippedSingle as string]);
    }
    setWord({ wordValue: "" });
};

所以我认为这会将字符串分离到, s处的数组中,循环数组,并将每个字符串推送到words useState数组。但它没有......这是发生的事情:

注意,字符串在, s处被正确分隔,并且代码确实循环了数组中的每一项,因为它们被成功地打印到控制台。问题是实际上只有最后一项被添加到words useState数组中。那么为什么不是所有拆分的字符串数组项都被添加到words中呢?

enyaitl3

enyaitl31#

因为setState是异步的,可以这样修复

setWords(prevWords => ([...prevWords, wordStrippedMulti as string]))
eqzww0vc

eqzww0vc2#

这是因为setState的异步行为。

这意味着你的setWords在这里是async,你在一个循环中使用它。这就是为什么它只设置循环的最后一个迭代值。
因此,只需将if块逻辑更改为:

if (word.wordValue.includes(',')) {
        const wordParsed = word.wordValue.split(',');
        let tempWords = []; 
        for (const wordParsedIndividual in wordParsed) {
            const wordStrippedMulti = wordParsed[wordParsedIndividual].replace(/[^\w\s!?]/g, '');
            tempWords = [...tempWords, wordStrippedMulti]; 
            
        }
        setWords(tempWords); 
  }

了解有关setState async行为的更多信息:https://stackoverflow.com/a/36087156/5939058

gijlo24d

gijlo24d3#

setWords不应该在for循环中使用,因为它不是一个立即命令,并且会有延迟。
如文档中所述
单词不会有更新的值,这就是它只显示最后插入的元素的原因。相反,您可以维护一个变量,并在循环结束执行时将其添加到状态中。

const newWords = []; 
    for (const wordParsedIndividual in wordParsed) {
        const wordStrippedMulti = wordParsed[wordParsedIndividual].replace(/[^\w\s!?]/g, '');
        newWords = [...newWords, wordStrippedMulti]; 
        
    }
    setWords(newWords);

相关问题