Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/26.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React.js |如果我将setState作为回调函数传递,即使在解构道具之后,也会无限渲染_Javascript_Reactjs_React Hooks_Use Effect - Fatal编程技术网

Javascript React.js |如果我将setState作为回调函数传递,即使在解构道具之后,也会无限渲染

Javascript React.js |如果我将setState作为回调函数传递,即使在解构道具之后,也会无限渲染,javascript,reactjs,react-hooks,use-effect,Javascript,Reactjs,React Hooks,Use Effect,问题 我有一个子组件,它将一些按钮id名称配置为道具,根据这些配置呈现可选的HTML按钮,并将所选按钮的值(id)返回到useEffect挂钩下的回调函数。但是,它会导致无限渲染循环,因为我需要将道具作为依赖项数组传递。请注意,React.js希望我对道具进行分解,但即使我这样做,它仍然会导致无限的渲染循环 子组件 import React, {createRef, useState, useEffect} from "react"; const OptionButton

问题

我有一个子组件,它将一些按钮id名称配置为道具,根据这些配置呈现可选的HTML按钮,并将所选按钮的值(id)返回到useEffect挂钩下的回调函数。但是,它会导致无限渲染循环,因为我需要将道具作为依赖项数组传递。请注意,React.js希望我对道具进行分解,但即使我这样做,它仍然会导致无限的渲染循环

子组件

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
return(
    <OptionButton buttons={{"ButtonValue": "ButtonName", "Button2Value": "Button2Name"}} callback={(value) => this.setState({buttonState: value})} buttonClass="buttonclass"/>
)
import React,{createRef,useState,useffect}来自“React”;
const OptionButton=({按钮,按钮类,回调})=>{
const[value,setValue]=useState()
常数重构=[]
const buttonWidth=((100-(Object.keys(buttons.length-1))-((100-(Object.keys(buttons.length-1))%Object.keys(buttons.length))/Object.keys(buttons.length)
useffect(()=>{
如果(回调){
回调(值);
}
},[value,callback])
常量选择=(事件)=>{
event.target.style.backgroundColor=“#10CB81”
refArray.forEach((currentRef)=>{
if(currentRef.current.id!==event.target.id){
currentRef.current.style.backgroundColor=“#F5475D”
}
})
setValue(event.target.id)
}
返回(
{Object.entries(buttons).map((keyvalue)=>{
const newRef=createRef()
重新排列推送(newRef)
返回{keyvalue[1]}
})}
)
}
导出默认选项按钮
如您所见,我的子组件获取按钮配置为键值(按钮-值-按钮-名称)对,呈现这些按钮,当用户单击其中一个按钮时,它获取该按钮的id,使用useState钩子将其设置为“值”常量,然后将该值传递给父组件回调

父组件

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
return(
    <OptionButton buttons={{"ButtonValue": "ButtonName", "Button2Value": "Button2Name"}} callback={(value) => this.setState({buttonState: value})} buttonClass="buttonclass"/>
)
返回(
this.setState({buttonState:value})buttonClass=“buttonClass”/>
)
如果我在回调函数中不使用this.setState,就可以了。例如,如果我只是这样做

(值)=>console.log(值)

没有无限循环。据我所知,只有当我尝试使用setState时才会发生这种情况


我做错了什么?我怎样才能解决这个问题?提前感谢。

之所以有无限循环,是因为在
useffect
中有
callback
作为依赖项。您传递给组件的是在每个新渲染上传递一个新的回调函数,因此它总是进入
useffect
。既然您正在使用类,则将传递实例方法视为回调函数,而不是箭头函数as ./p>。
我还认为你过度使用了裁判。您还可以通过存储(例如单击按钮的id),然后动态设置所有按钮的样式(例如,
map
内部)来实现所做的操作。如果当前按钮的id与存储的相同,请在
样式
对象中使用#10CB81 bg颜色,否则使用不同的颜色


还有更好的方法来检查单击了哪个btn,请参阅。

callback.call(null,value)如何将useCallback钩子与类组件一起使用?@AlperenÖztürk更新了答案谢谢。多亏了他的回答,我已经解决了这个问题。我也不知道使用裁判太多被认为是一种不好的做法。我会检查你的建议。@AlperenÖztürk,你接受的答案是错误的,原因是我在其他评论中解释的(PS关于参考文献,这不是不好的做法,只是不建议过度使用)现在尝试了你的解决方案。工作如期进行。