Javascript React.js |如果我将setState作为回调函数传递,即使在解构道具之后,也会无限渲染
问题 我有一个子组件,它将一些按钮id名称配置为道具,根据这些配置呈现可选的HTML按钮,并将所选按钮的值(id)返回到useEffect挂钩下的回调函数。但是,它会导致无限渲染循环,因为我需要将道具作为依赖项数组传递。请注意,React.js希望我对道具进行分解,但即使我这样做,它仍然会导致无限的渲染循环 子组件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
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关于参考文献,这不是不好的做法,只是不建议过度使用)现在尝试了你的解决方案。工作如期进行。