简体   繁体   English

如何使用 useState 钩子计算数组中项目的频率(React useState 钩子)?

[英]How to use the useState hook to count frequencies of items in an array(React useState hook)?

I'm trying to solve this exercise where the array contains 10 objects such as我正在尝试解决这个数组包含 10 个对象的练习,例如

arr = [{txt: "txt1", color: "red"},

{txt: "txt2", color: "green"}, {txt: "txt3", color: "blue"},...] {txt:“txt2”,颜色:“绿色”},{txt:“txt3”,颜色:“蓝色”},...]

When I click a button, it should show up a random color which I know how to do but I'm not sure how to also show how many times each color shows up.当我单击一个按钮时,它应该显示一种我知道该怎么做的随机颜色,但我不确定如何也显示每种颜色出现的次数。

I set up my function as below:我将我的 function 设置如下:

const countColors = (props) => {
   

const arr = [{txt: "txt1", color: "red"},
{txt: "txt2", color: "green"}, {txt: "txt3", color: "blue"},...]

const [count, setCount] = useState(0);

const choice = () => {
    const randIdx = Math.floor(Math.random() * arr.length);
    return arr[randIdx];
};

const updateScore = () => {
        let randColor = choice(props.arr).color;
        if (randColor === 'red') {
            return setCount((count) => count + 1)
        } else if (randColor === 'green') {
            return setCount((count) => count + 1);
        } else {
            return setCount((count) => count + 1);
        }
    };
const clickHandler = () => {
setCount(updateScore);
}

return (
    <ul>
        <li>Red Counts: {updateScore}</li>
        <li>Green Counts: {updateScore}. 
        </li>
        <li>Blue Counts: {updateScore}</li>
    </ul> 
    <button onClick={clickHandler}>Click</button>

 )
};

I keep getting "NaN" or "undefined" when I check the state with the react dev tool.当我使用反应开发工具检查 state 时,我不断收到“NaN”或“未定义”。

I wonder if I need to set up 3 states for counting each color.我想知道是否需要设置 3 个状态来计算每种颜色。

This is what you need to do:这是你需要做的:

const[redCount,setRedCount]=useState(0);
//similarily for other colors
const clickHandler = () => {
let randColor = choice(props.arr).color;
if (randColor === 'red') {
            setRedCount(redCount+1);
    //similairly do it for other colors

}

return (
    <ul>
        <li>Red Counts: {redCount}</li>
        //similarily for other colors
    </ul> 
    <button onClick={clickHandler}>Click</button>

 )
import React, { useState } from "react";

const CountColors = (props) => {
    const arr = [
        { txt: "txt1", color: "red" },
        { txt: "txt2", color: "green" },
        { txt: "txt3", color: "blue" },
    ];

    const colors = {};
    arr.forEach((item) => {
        colors[item.color] = 0;
    });
    const [count, setCount] = useState(colors);

    const choice = () => {
        const randIdx = Math.floor(Math.random() * arr.length);
        return arr[randIdx];
    };

    const clickHandler = () => {
        let randColor = choice(props.arr).color;
        console.log(randColor);
        setCount((prevCount) => ({
            ...prevCount, // to presist the old data in the state (spread operator)
            [randColor]: prevCount[randColor] + 1, 
        }));
    };

    return (
        <>
            <ul>
                {arr.map((item) => (
                    <li>{item.color} count: {count[item.color]}</li>
                ))}
            </ul>
            <button onClick={clickHandler}>Click</button>
        </>
    );
};

export default CountColors;

Try this code it should work for the scenario you asked for.试试这个代码,它应该适用于您要求的场景。

There are two ways to achieve this problem有两种方法可以解决这个问题

  1. By creating a separate state for each and every color in an array.通过为数组中的每种颜色创建单独的 state。
  2. By creating an array and storing their current value by mapping their index with the arr .通过创建一个数组并通过将它们的索引映射到arr来存储它们的当前值。
  3. Dynamically creating an object with the color name as key and count as value(recommended).动态创建 object,颜色名称为键,计数为值(推荐)。

Because the accessing time (read and write) of the value is very fast while using an object compared with an array in this scenario though we don't know the index at the first point.因为在这种情况下,与数组相比,使用 object 时值的访问时间(读取和写入)非常快,尽管我们不知道第一点的索引。

What I have done here is that我在这里所做的是

  1. At first I have created an empty object named colors for looped through the arr array and set the key as color name and set the default value 0.首先,我创建了一个名为colors的空 object 用于循环遍历arr数组并将键设置为颜色名称并设置默认值 0。

  2. On each click event depending upon the choice I have incremented the value and the reason I used spread operator is that the value in useState is mutable.在每个点击事件上,根据选择,我增加了值,我使用扩展运算符的原因是 useState 中的值是可变的。

  3. Finally in the return statement I have looped through the array and printed the item color name as well as the value which makes the code look good.最后,在返回语句中,我遍历了数组并打印了项目颜色名称以及使代码看起来不错的值。

I have two things that might help you in the future我有两件事将来可能会对你有所帮助

  1. The class/function name should start with a capital letter.类/函数名称应以大写字母开头。
  2. Always returned HTML components should be wrapped with empty tags or React.Fragment.总是返回 HTML 组件应该用空标签或 React.Fragment 包装。

Just to double check if I understand this correctly: You have an array of colours and text.只是为了仔细检查我是否理解正确:您有一组颜色和文本。 You want to click on a button which will select a random color and tell you how many times said color appears.您想单击一个按钮,该按钮将 select 随机颜色并告诉您该颜色出现了多少次。 Assuming that is correct, one of the things that stands out from your code is the following blocks:假设这是正确的,您的代码中突出的一件事是以下块:

const [count, setCount] = useState(0);
....

const updateScore = () => {
        let randColor = choice(props.arr).color;
        if (randColor === 'red') {
            return setCount((count) => count + 1)
        } else if (randColor === 'green') {
            return setCount((count) => count + 1);
        } else {
            return setCount((count) => count + 1);
        }
    };

First of all, notice how you always use the same state, count .首先,请注意您如何始终使用相同的 state, count Assuming this was correctly used, you will always override that state, meaning every time you begin the count of a new color, it will start again.假设这被正确使用,您将始终覆盖 state,这意味着每次您开始计算新颜色时,它都会重新开始。

Secondly, the manner in which you are using the setCount .其次,您使用setCount的方式。 The state setter function does not expect a function as a parameter, but the actual value you want. state 设置器 function 不期望 function 作为参数,而是您想要的实际值。 To fix this initial proble, the proper set of the count should be done as:要解决此初始问题,应按以下方式完成正确的计数集:

setCount(count + 1)设置计数(计数 + 1)

However, this is where my first point comes to play: every time you try to set a new count, it will reset that of another color.然而,这是我的第一点要发挥的地方:每次您尝试设置新计数时,它都会重置另一种颜色的计数。 So this is no good either.所以这也不好。

Now, this leaves you with two choices: you can add a separate setXCount for each color as you suggested, (setRedCount, setBlueCount, etc), or you could through them all into an object so that you have it all in single state and don't require a new one be added every time there is a new color.现在,这给您留下了两个选择:您可以按照您的建议为每种颜色添加一个单独的setXCount (setRedCount、setBlueCount 等),或者您可以将它们全部放入 object 中,这样您就可以将它们全部放在单个 state 中并不要每次有新颜色时都不需要添加新颜色。 Something like this:像这样的东西:

    const [countPerColor, setCountPerColor] = React.useState({});
    ...
    const updateScore = () => {

     const randColor = choice(arr).color;

        if (countPerColor[randColor]){
          countPerColor[randColor] ++
        } else {
          countPerColor[randColor] = 1
        }

        setCountPerColor({...countPerColor})
     };

Obviously, your return statement will need to be updated accordingly:显然,您的退货声明将需要相应更新:

...
        <li>Red Counts: {countPerColor.red || 0}</li>
        <li>Green Counts: {countPerColor.green || 0}. 
        </li>
        <li>Blue Counts: {countPerColor.blue || 0}</li>

And now to conclude, here is a functioning demo of the app.现在总结一下,这是该应用程序的功能演示。

 const App = (props) => { const arr = [ {txt: "txt1", color: "red"}, {txt: "txt2", color: "blue"}, {txt: "txt3", color: "blue"}, {txt: "txt4", color: "red"}, {txt: "txt5", color: "green"}, {txt: "txt6", color: "red"}, {txt: "txt7", color: "green"}, {txt: "txt8", color: "green"}, {txt: "txt9", color: "red"}, {txt: "txt10", color: "blue"}, ] const [countPerColor, setCountPerColor] = React.useState({}); const choice = () => { const randIdx = Math.floor(Math.random() * arr.length); return arr[randIdx]; }; const updateScore = () => { let randColor = choice(arr).color; if (countPerColor[randColor]){ countPerColor[randColor] ++ } else { console.warn('exists', randColor) countPerColor[randColor] = 1 } setCountPerColor({...countPerColor}) }; return ( <div> <ul> <li>Red Counts: {countPerColor.red || 0}</li> <li>Green Counts: {countPerColor.green || 0}. </li> <li>Blue Counts: {countPerColor.blue || 0}</li> </ul> <button onClick={() => updateScore()}>Click me</button> </div> ) } ReactDOM.render( <App />, document.getElementById('app') );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script> <div id="app"></div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM