I'm really confused on how to do useState
in React on an empty array
import "./styles.css";
import text from "./text.js";
import React, { useState } from "react";
export default function App() {
let allTheWords = text.split(" ");
let countData = [];
let theWordCount = {};
const createTable = () => {
for (const num of allTheWords) {
theWordCount[num] = theWordCount[num] ? theWordCount[num] 1 : 1;
}
for (const property in theWordCount) {
countData.push(
<tr key={property}>
<td>{property}</td>
<td>{theWordCount[property]}</td>
</tr>
);
}
};
createTable();
const sortWords = () => {
theWordCount = Object.entries(theWordCount)
.sort(([, a], [, b]) => a - b)
.reduce((r, [k, v]) => ({ ...r, [k]: v }), {});
console.log("OKAY I THINK WE SORTED: " JSON.stringify(theWordCount));
createTable();
};
return (
<div>
<button onClick={sortWords}>SORT WORDS</button>
<table>
<tbody>
<tr>
<th>Word</th>
<th>Count</th>
</tr>
{countData}
</tbody>
</table>
</div>
);
}
I need to somehow do useState
on the variable countData
so I can update the DOM when theWordCount
changes.
https://reactjs.org/docs/hooks-state.html
I read through the above and got to this
import "./styles.css";
import text from "./text.js";
import React, { useState } from "react";
export default function App() {
let allTheWords = text.split(" ");
let countData = [];
let theWordCount = {};
countData = useState(0);
const createTable = () => {
for (const num of allTheWords) {
theWordCount[num] = theWordCount[num] ? theWordCount[num] 1 : 1;
}
for (const property in theWordCount) {
countData.push(
<tr key={property}>
<td>{property}</td>
<td>{theWordCount[property]}</td>
</tr>
);
}
};
createTable();
const sortWords = () => {
theWordCount = Object.entries(theWordCount)
.sort(([, a], [, b]) => a - b)
.reduce((r, [k, v]) => ({ ...r, [k]: v }), {});
console.log("OKAY I THINK WE SORTED: " JSON.stringify(theWordCount));
createTable();
};
return (
<div>
<button onClick={sortWords}>SORT WORDS</button>
<table>
<tbody>
<tr>
<th>Word</th>
<th>Count</th>
</tr>
{countData}
</tbody>
</table>
</div>
);
}
But the DOM doesn't update or do anything or give me any errors.
In this context how do you make countData
converted into a state in the function?
CodePudding user response:
To create an array called countData
in your component's state, the syntax would look something like this:
const [countData, setCountData] = useState([]);
Now, as far as I'm aware, it's considered bad practice to "mutate" (aka edit) state directly. This is what the setCountData
function returned by useState is for.
So, instead of pushing to the array directly with countData.push()
, you would want to make a clone of this array, and use setCountData()
to update the state with the cloned array.
For example,
// This will be our "cloned" array that we will use in setCountData()
let newArray = countData;
// Push to this array instead of countData
newArray.push('something here');
// Then, update the countData array using setCountData() with this array we just created
setCountdata(newArray);
CodePudding user response:
const [countData, setCountData] = useState([]);
//When you need modify array:
let row = '<tr>....</tr>';
setCountData((current)=>[...current, row])
CodePudding user response:
You should
Keep the state value consistent, to make manipulation of it easy - for example, if you use
useState(0)
, further uses of that state variable should be a number. But that's not what you have here - theuseState
argument should correspond to the type of state value you're usingReact components shouldn't be put into state. Instead, state should be composed of (usually serializable) plain JavaScript values whenever possible, and then transformed into JSX when rendering.
useState
returns an array containing two values: the state as the first value, and the state setter as the second value. Call the state setter to update the state. Since it looks like an array of objects most closely resembles the sort of state you'd want to work with, this:let countData = []; let theWordCount = {}; countData = useState(0);
should be changed to
const [words, setWords] = useState([])
where the
words
array contains objects withword
andcount
properties.Or, have a function that transforms the initial props into the array structure, then passes that to
useState
.
const textToWords = (text) => {
const wordsMap = {};
for (const word of text.split(' ')) {
wordsMap[word] = (wordsMap[word] || 0) 1;
}
return Object.entries(wordsMap)
.map(([word, count]) => ({ word, count }));
};
const [wordsArr, setWordsArr] = useState(() => textToWords(text));
// And when rendering, instead of {countData}:
{wordsArr.map(({ word, count }) => (
<tr>
<td>{word}</td>
<td>{count}</td>
</tr>
))}
To set the state, sort the array (after cloning it, to avoid mutation), then call setWordsArr
.
const sortWords = () => {
setWordsArr(
wordsArr
.slice()
.sort((a, b) => a.count - b.count)
);
};