I have the following React code:
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
I have a text box that pushes inputs words into words
, which is a useState array, on button press. This is what it looks like in action:
I modified handleWordSubmit
to allow for adding several words at a time to the words
useState array by separating input string at ,
values and pushing all of these array values one-at-a-time.
Now it looks like this:
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(/[^ws!?]/g, '');
console.log(wordStrippedMulti);
setWords([...words, wordStrippedMulti as string])
}
} else {
const wordStrippedSingle = word.wordValue.replace(/[^ws!?]/g, '');
setWords([...words, wordStrippedSingle as string]);
}
setWord({ wordValue: "" });
};
So I thought that this would separate the string into an array at the ,
s, loop over the array, and push every individual string to the words
useState array. But it doesn’t… This is what happened:
Notice that the string is properly separated at the ,
s and the code does loop over every item in the array because they are successfully printed to the console. The problem is that only the last item is actually added to the words
useState array. So why aren’t all of the split string array items added to words
?
3
Answers
This is happening because of the async behavior of setState.
That means your
setWords
isasync
here and you are using it in a loop. And that is why it is only setting the last iteration value of the loop.So just change the if block logic to this:
Understand more about setState async behavior: https://stackoverflow.com/a/36087156/5939058
Because setState is asynchronous. You can fix it like this
setWords should not be used inside a for loop as it is not an immediate command, and there’s a delay involved.
As explained in the docs
The words won’t have the updated value, and that’s the reason it will only show the last inserted element inside.
Instead, you can maintain a variable and add it to the state once the loop ends executing.