调用 React Setstate 回调但延迟渲染
Posted
技术标签:
【中文标题】调用 React Setstate 回调但延迟渲染【英文标题】:React Setstate callback called but render delayed 【发布时间】:2021-04-21 18:19:43 【问题描述】:我 2 天前刚开始学习反应,我很难使用反应的 setstate
方法,我只知道如果想根据以前的状态更改状态,请使用 revstate
参数和回调参数在状态更改后立即执行(如果错误请纠正我),所以我只是更改数组内容(我使用 javascript 的array.map
渲染它)并且我希望它在状态更改后立即渲染,它正在改变但是延迟了,它仅在我再次单击后才渲染,但调用了渲染方法
感谢任何前辈的帮助。
处理单击以根据我的按钮“onClick”上传递的索引更改以呈现内容
class App extends React.Component
constructor(props)
super(props)
this.state =
clickeditem : -1
this.torender = [
display : "first",
content : []
,
display : "second",
content : []
]
handleclick = (i) =>
this.setState(prevstate=>
if (prevstate.clickeditem === -1)
return clickeditem : i
else
return prevstate.clickeditem === i ? clickeditem : -1 : clickeditem : i
,() =>
return this.state.clickeditem === -1 ? (this.torender[0].content = [], this.torender[1].content = [])
: (this.state.clickeditem === 0) ? (this.torender[0].content = ["torender-0 content","torender-0 content"],this.torender[1].content = [])
: (this.state.clickeditem === 1) ? (this.torender[1].content = ["torender-1 content","torender-1 content"],this.torender[0].content = [])
: null
)
render()
return(
<div>
<ul>
this.torender.map((item,index) =>
return(
<li key = index>
item.display
<ul>
item.content.map((content,contentindex) =>
return(<li key = contentindex>content</li>)
)
</ul>
</li>
)
)
</ul>
<button onClick=()=>this.handleclick(0)>first-button</button>
<button onClick=()=>this.handleclick(1)>second-button</button>
</div>
)
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
【问题讨论】:
this.torender
不是反应状态的一部分,组件需要再次重新渲染才能看到您在上一个渲染周期中所做的突变。如果您将其作为状态的一部分,或者更好,只需在渲染 UI 时计算它的值,那么它应该可以工作。
【参考方案1】:
重构您的代码并使用更简单的方法
其实你不应该使用第二个参数callback
。
每当状态发生变化时,React Js 的生命周期都会重新正确渲染(详细看下图说明^^!)
有几点需要注意:
相应地移动torender
中每个项目的内容-->这对初始数据更清楚,并且不应该被改变。
默认clickeditem
是torender
中的一项,例如第一项。
之后,你只需控制要以这种方式呈现的内容
___________ The condition to call renderContent() method ______________
index === this.state.clickeditem && this.renderContent(item)
_____________renderContent() looks like below_____________
renderContent = (item) =>
return (
<ul>
item.content.map((content, contentindex) =>
return <li key=contentindex>content</li>;
)
</ul>
);
;
class App extends React.Component
constructor(props)
super(props);
this.state =
clickeditem: 0
;
this.torender = [
display: "first",
content: ["torender-0 content", "torender-0 content"]
,
display: "second",
content: ["torender-1 content", "torender-1 content"]
];
handleclick = (index) =>
this.setState(clickeditem: index);
;
renderContent = (item) =>
return (
<ul>
item.content.map((content, contentindex) =>
return <li key=contentindex>content</li>;
)
</ul>
);
;
render()
return (
<div>
<ul>
this.torender.map((item, index) =>
return (
<li key=index>
item.display
index === this.state.clickeditem && this.renderContent(item)
</li>
);
)
</ul>
<button onClick=() => this.handleclick(0)>first-button</button>
<button onClick=() => this.handleclick(1)>second-button</button>
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"> </div>
【讨论】:
比我的解决方案更清洁,我认为如果您添加了关于torender
突变以及为什么需要额外的渲染周期的类似解释,那么您将获得适当完整的答案。
@Phong 我发现这个组件生命周期非常有用,非常感谢 gbu!【参考方案2】:
问题
this.torender
不是反应状态的一部分,组件需要再次重新渲染才能看到您在上一个渲染周期中所做的突变。
解决方案
最好在渲染 UI 时计算它的值,然后它应该可以按照我怀疑的那样工作。
handleclick = (i) =>
this.setState(prevstate=>
if (prevstate.clickeditem === -1)
return clickeditem: i
else
return prevstate.clickeditem === i ? clickeditem: -1 : clickeditem: i
)
render()
const clickeditem = this.state;
let torender = [
display : "first",
content : []
,
display : "second",
content : []
];
if (clickeditem === -1)
torender[0].content = [];
torender[1].content = [];
else if (clickeditem === 0)
torender[0].content = ["torender-0 content","torender-0 content"];
torender[1].content = [];
else if (clickeditem === 1)
torender[1].content = ["torender-1 content","torender-1 content"];
torender[0].content = [];
else
torender = []; // <-- render nothing
return(
<div>
<ul>
torender.map((item,index) =>
return(
<li key = index>
item.display
<ul>
item.content.map((content, contentindex) => (
<li key=contentindex>content</li>;
))
</ul>
</li>
)
)
</ul>
<button onClick=()=>this.handleclick(0)>first-button</button>
<button onClick=()=>this.handleclick(1)>second-button</button>
</div>
)
【讨论】:
以上是关于调用 React Setstate 回调但延迟渲染的主要内容,如果未能解决你的问题,请参考以下文章
在回调函数中使用 setState 挂钩时反应过多的重新渲染
无法在 socket.io 回调 React.js 中调用 setState