简体   繁体   English

React Function 组件不更新视图 onClick

[英]React Function Component doesn't update view onClick

I'm new to React.我是反应新手。 I have a rating component that I created.我有一个我创建的评级组件。 The problem I'm having is onClick I can see the rating is updating in the console, but on the page I don't see the change happening.我遇到的问题是 onClick 我可以在控制台中看到评级正在更新,但在页面上我没有看到发生的变化。 My understanding is that React components need to be pure functions and it's better to prefer functional components over classes.我的理解是 React 组件需要是纯函数,最好是函数式组件而不是类。 When I try to use the useState hook my rating is added to the previous state and doesn't update correctly on the page.当我尝试使用 useState 挂钩时,我的评分被添加到之前的 state 并且没有在页面上正确更新。

My first question is what is the best/preferred way to update state within a component?我的第一个问题是在组件中更新 state 的最佳/首选方法是什么? If I'm using a functional component do I have to use a hook?如果我使用的是功能组件,我必须使用钩子吗?

Please see my code below请在下面查看我的代码

export default function Rating(props) {
    let stars = [];
    // const [stars, setStars] = useState([]);
    let star = '☆';

    for (let i = 0; i < props.stars; i++) {
        stars.push(star);
    }

    function rate(index) {
        let filledStar = '★'
        let stars = [];
        // setStars([])


        for (let i = 0; i < props.stars; i++) {
            stars.push(star);
        }
        stars.forEach((star, i) => {
            while (index >= 0) {
                stars[index] = filledStar;
                index--;
            }

        })
        console.log('stars filled', stars)
        return stars

     }

    return (
        <>
        <div className="stars">
            {stars.map((star, i) => (
                <h2 
                    key={i}
                    onClick={() => rate(i)}>{star}
                </h2>
            ))}
        </div>

        </>

    )

}

如果我单击第四颗星,则会按预期返回,但 UI 不会更新

If I click the fourth star this is returned as expected, but the UI doesn't update.如果我单击第四颗星,则会按预期返回,但 UI 不会更新。

As you suggested, you will need to use hooks in order to seek the functionality you're looking for (or use a class component).正如您所建议的,您需要使用挂钩来寻找您正在寻找的功能(或使用 class 组件)。 In your current implementation, you're not actually using React states, so React doesn't know that you want it to re-render your component.在您当前的实现中,您实际上并没有使用 React 状态,因此 React 不知道您希望它重新渲染您的组件。 Also, the stars array you're using in rate() is different from the stars array in your component.此外,您在 rate() 中使用的 stars 数组与组件中的 stars 数组不同。 You don't seem to be making use of the stars array created and returned by rate()您似乎没有使用由 rate() 创建和返回的 stars 数组

How exactly have you tried to use useState?您究竟是如何尝试使用 useState 的?

Here's a working version that fills in stars up to and including the star that was clicked on - using useState , and useEffect .这是一个工作版本,它使用useStateuseEffect填充星号,包括被点击的星号。

 const { Fragment, useEffect, useState } = React; function Rating(props) { // Set state as an empty array const [stars, setStars] = useState([]); // Called by useEffect his function // creates a new array of empty stars function initStars() { const stars = []; for (let i = 0; i < +props.stars; i++) { stars.push('☆'); } setStars(stars); } // Called when the component // first mounts, and called only once useEffect(() => { initStars(); }, []); function rate(e) { // Get the id from the star dataset const { id } = e.target.dataset; // Create a fresh array const stars = []; // Loop; if the current index is less or // equal to the id set it as a filled star // otherwise set it to an empty star for (let i = 0; i < +props.stars; i++) { stars.push(i <= +id? '★': '☆'); } // Set the state with the new array setStars(stars); } return ( <Fragment> <div> {stars.map((star, i) => ( <span className="star" key={i} data-id={i} onClick={rate} >{star} </span> ))} </div> </Fragment> ); }; ReactDOM.render( <Rating stars="10" />, document.getElementById('react') );
 .star { font-size: 1.8em; }.star:hover { cursor: pointer; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script> <div id="react"></div>

So, it seems that I need to use the useState hook.所以,看来我需要使用 useState 钩子。 I'm sure there is another way to do this, but this worked for me.我敢肯定还有另一种方法可以做到这一点,但这对我有用。

 export default function Rating(props) {
        const [stars, setStars] = useState([]);
        let star = '☆';

        function initStars() {
            const stars = [];
            for (let i = 0; i < props.stars; i++) {
               stars.push(star);
            }
            setStars(stars);
        }

        // Called when the component
        // first mounts, and called only once
        useEffect(() => {
            initStars();
        }, []);

        function rate(index) {
            console.log('index', index);
            let filledStar = '★'
            let stars = [];

            console.log('setStars', stars);

            for (let i = 0; i < props.stars; i++) {
               stars.push(star);
            }
            stars.forEach((star, i) => {
                while (index >= 0) {
                   stars[index] = filledStar;
                   index--;
                }

            })
            console.log('stars filled', stars)
            // return stars
            setStars(stars)

         }

         // console.log('stars', stars);

        return (
        <>
            <div className="stars">
                {stars.map((star, i) => (
                    <h2 
                        key={i}
                        onClick={() => rate(i)}>
                        {star}
                    </h2>
                ))}
            </div>

        </>

    )

}

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

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