简体   繁体   English

反应.js | 如果我将 setState 作为回调 function 传递,则无限渲染,即使在解构道具之后也是如此

[英]React.js | Infinite render if I pass setState as a callback function, even after destructuring props

Issue问题

I have a child component that gets some button id-name configs as props, renders selectable HTML buttons according to those configs and returns the selected button's value(id) to the callback function under a useEffect hook.我有一个子组件,它获取一些按钮 id-name 配置作为道具,根据这些配置呈现可选的 HTML 按钮,并将所选按钮的值(id)返回给 useEffect 挂钩下的回调 function。 However it causes an infinite render loop because I need to pass the props as a dependency array.但是它会导致无限渲染循环,因为我需要将道具作为依赖数组传递。 Note that React.js wants me to destructure props, but it still causes an infinite render loop even if I do that.请注意,React.js 希望我解构 props,但即使我这样做,它仍然会导致无限渲染循环。

Child Component子组件

import React, {createRef, useState, useEffect} from "react";

const OptionButton = ({ buttons, buttonClass, callback }) => {

    const [value, setValue] = useState()
    const refArray = []
    const buttonWidth = ((100 - (Object.keys(buttons).length - 1)) - ((100 - (Object.keys(buttons).length - 1)) % Object.keys(buttons).length)) / Object.keys(buttons).length

    useEffect(() => {
        if (callback) {
            callback(value);
        }
    }, [value, callback])

    const select = (event) => {
        event.target.style.backgroundColor = "#10CB81"
        refArray.forEach((currentRef) => {
            if (currentRef.current.id !== event.target.id) {
                currentRef.current.style.backgroundColor = "#F5475D"
            }
        })
        setValue(event.target.id)
    }

    return(
        <span style={{display: "flex", justifyContent: "space-between"}}>
            {Object.entries(buttons).map((keyvalue) => {
                const newRef = createRef()
                refArray.push(newRef)
                return <button ref={newRef} id={keyvalue[0]} key={keyvalue[0]} className={buttonClass} onClick={select} style={{width: `${buttonWidth}%`}}>{keyvalue[1]}</button>
            })}
        </span>
    )
}

export default OptionButton

So as you can see here my child component gets button configs as key-value (button value-button name) pairs, renders these buttons and when user clicks one of these buttons it gets the id of that button, sets it to 'value' constant using useState hook and then passes that value to parent component callback.因此,正如您在此处看到的,我的子组件将按钮配置作为键值(按钮值-按钮名称)对,呈现这些按钮,当用户单击其中一个按钮时,它会获取该按钮的 id,将其设置为“值”常量使用 useState 钩子,然后将该值传递给父组件回调。

Parent Component父组件

return(
    <OptionButton buttons={{"ButtonValue": "ButtonName", "Button2Value": "Button2Name"}} callback={(value) => this.setState({buttonState: value})} buttonClass="buttonclass"/>
)

It's just fine if I don't use this.setState at the callback function.如果我不在回调 function 中使用 this.setState 就好了。 For example if I just do例如,如果我只是这样做

(value) => console.log(value) (值)=> 控制台日志(值)

there is no infinite loop.没有无限循环。 As far as I can tell it only happens if I try to use setState.据我所知,只有当我尝试使用 setState 时才会发生这种情况。

What am I doing wrong?我究竟做错了什么? How can I fix this?我怎样才能解决这个问题? Thanks in advance.提前致谢。

The reason why there is infinite loop is because you have callback as dependency in useEffect .存在无限循环的原因是因为您在useEffect中有callback作为依赖项。 And what you are passing to the component is you pass a new callback function on each new render , hence it always enters useEffect because of that.你传递给组件的是你在每个新的渲染上传递一个新的callback function ,因此它总是因此进入useEffect Since you are using classes consider passing instance method as callback instead of arrow function as here .由于您使用的是类,请考虑将实例方法作为回调而不是箭头 function 作为此处传递。


Also I think you are overusing refs.另外,我认为您过度使用了 refs。 You could also achieve what you are doing by just storing say the id of clicked button, and then dynamically styling all buttons, eg inside map if id of current button is same as the one stored, use #10CB81 bg color in style object, otherwise different one.您还可以通过存储说单击按钮的 id 来实现您正在做的事情,然后动态设置所有按钮的样式,例如在map内部,如果当前按钮的 id 与存储的相同,则使用style object 中的#10CB81 bg 颜色,否则不同的。

Also there are better ways to check which btn was clicked, see here .还有更好的方法来检查单击了哪个 btn,请参见此处

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

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