【问题标题】:Child components re-rendering on parent re-render子组件在父组件重新渲染时重新渲染
【发布时间】:2019-06-01 11:37:08
【问题描述】:

我对 react 还很陌生,我一直在拆解一个 web 应用程序并用 react 组件替换部分。我现在正在开发一个包含我创建的一些不同组件的组件。

在新组件中,我在 componentDidMount 函数中调用 API 并创建子组件。乍一看,一切看起来都很完美,但是当我们在其中一个子组件中进行状态更改然后在父组件中进行更改时,子组件会将其状态重置为更改之前的状态。

我了解状态没有传递给父级的情况,但我不确定是否有我只是缺少的设计,或者我是否需要移动到 redux 商店来制作这个工作

class Frame extends Component{
constructor(props){
    super(props);
    this.state = {
       tab: "tab1",
       tab1: null,
       tab2: null,
   }
}
componentDidMount() {
   let data = this.props.service.getData();
   let tab1 = (<Tab1 {...data} />);
   let tab2 = (<Tab2 {...data} />);
   this.setState({tab1:tab1, tab2:tab2});
}

render(){
    if (!this.state.tab1 || !this.state.tab2){
         return (<div>Loading</div>)
    }

    return (
        <ul>
            <li onClick={()=>{this.setState({tab:"tab1"})}}></li>
            <li onClick={()=>{this.setState({tab:"tab2"})}}></li>
        <ul>
        <div>
               {this.state.tab === "tab1" &&
                    this.state.tab1
                }

                {this.state.tab === "tab2" &&
                    this.state.tab2
                }
         </div>
    )
}
}

【问题讨论】:

  • 您在每次选项卡更改时卸载子组件,因此它们的本地状态丢失。您应该始终呈现子组件(也许只是隐藏它们)或将它们的状态保留在父组件中。另外一点,将数据保留在组件中而不是渲染组件中可能会更好
  • 这行得通。我只是移动了 if 逻辑以使用 css 类隐藏它们。以便它们仅呈现一次,因为 if 逻辑不会停止其他选项卡的呈现。谢谢

标签: reactjs


【解决方案1】:

axnyff,评论是解决方案。 if 将在渲染中再次实例化该对象,因为它以前不存在。如果我使用 css 类来隐藏它们,它们只会被实例化一次,因为

class Frame extends Component{
  constructor(props){
      super(props);
      this.state = {
         tab: "tab1",
         tab1: null,
         tab2: null,
     }
  }
  componentDidMount() {
     let data = this.props.service.getData();
     let tab1 = (<Tab1 {...data} />);
     let tab2 = (<Tab2 {...data} />);
     this.setState({tab1:tab1, tab2:tab2});
  }

  render(){
      if (!this.state.tab1 || !this.state.tab2){
           return (<div>Loading</div>)
      }

      return (
          <ul>
              <li onClick={()=>{this.setState({tab:"tab1"})}}></li>
              <li onClick={()=>{this.setState({tab:"tab2"})}}></li>
          <ul>
          <div>
                 <div class=> {this.state.tab !== "tab1" && "hidden"}>
                      {this.state.tab1}
                 </div> 

                 <div class=> {this.state.tab !== "tab2" && "hidden"}>
                      {this.state.tab2}
                 </div>
           </div>
      )
  }
}

【讨论】:

    【解决方案2】:

    编写一个设置状态的点击处理程序,并调用它 onClick 而不是直接在渲染中设置状态。

    【讨论】:

      【解决方案3】:

      您使用的有点不同。你应该设置数据。 componentDidMount 也只能使用一次。

      class Frame extends Component {
      constructor(props) {
       super(props);
       this.state = {
        tab: 'tab1',
        data: null,
       };
      }
      componentDidMount() {
       let data = this.props.service.getData();
       if (data) {
         this.setState({ data });
       }
      }
      
      render() {
      if (this.state.data) {
        return <div>Loading</div>;
      }
      
      return (
        <div>
          <ul>
            <li
              onClick={() => {
                this.setState({ tab: 'tab1' });
              }}
            />
            <li
              onClick={() => {
                this.setState({ tab: 'tab2' });
              }}
            />
          </ul>
          <div>
            {this.state.tab === 'tab1' && <Tab {...this.state.data} />}
            {this.state.tab === 'tab2' && <Tab {...this.state.data} />}
          </div>
        </div>
        );
       }
       }
      

      【讨论】: