已调用 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>