已调用 React Setstate 回调但呈现延迟
React Setstate callback called but render delayed
我两天前才开始学习反应,我很难使用反应的 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 时计算它的值,然后它应该会像我怀疑的那样工作。
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>
)
}
}
重构您的代码并采用更简单的方法
实际上,您不应该使用第二个参数 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>
我两天前才开始学习反应,我很难使用反应的 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 时计算它的值,然后它应该会像我怀疑的那样工作。
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>
)
}
}
重构您的代码并采用更简单的方法
实际上,您不应该使用第二个参数 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>