user1320691
user1320691

Reputation: 83

Child components re-rendering on parent re-render

I am fairly new to react and I have been taking apart a web application and replacing parts with react components. I am now working on a component that holds a few of the different components that I created.

In the new component I make an API call in the componentDidMount function and create the children components. At first glance everything looks perfect, but when we make a state change in one of the child components then make a change in the parent component the children components reset their state to how they were before the changes.

I understand whats going on that the state isn't being passed to the parent, but I'm not sure if there a design for this that I am just missing or if I need to move to a redux store to make this work

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>
    )
}
}

Upvotes: 0

Views: 172

Answers (3)

user1320691
user1320691

Reputation: 83

axnyff, comment was the solution. The if would instantiate the object again in render since it wasn't there before. If I used a css class to hide them they will only be instantiated once since

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>
      )
  }
}

Upvotes: 1

Yasin Tazeoglu
Yasin Tazeoglu

Reputation: 1014

You are using a little different . You should set the data . Also componentDidMount works only once.

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>
  );
 }
 }

Upvotes: 0

stever
stever

Reputation: 1241

Write a click handler that sets state, and call it onClick rather than setting state directly in render.

Upvotes: 0

Related Questions