Jonny
Jonny

Reputation: 1283

Best practice way to set state from one component to another in React

I am asking this question from a best practice point of view - the answers I've found on here are about more specific problems to an individual code base. I am happy to be pointed in the right direction if it's already been answered or to be shown another way if what I am attempting is not considered good practice - I may have misunderstood some concepts...

I am learning React and am building a simple app using it. Mainly in order to keep my code tidy, I have created two files. First file - I access an API from inside my component and render some data from my components state. Second file - I want to use the same info from the components state in my first file and use that as props in my second file.

A simplified example is below.

First file:

import React, { Component } from 'react';
import SecondComponent from './SecondComponent';

function DisplayFirstData (props) {
  return (
    {props.data}
}

class FirstComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      myData: something,
    }
  }
  render() {
    <DisplayFirstData data={this.state.myData} />
  }
}

Second component:

import React, { Component } from 'react';

function DisplaySecondData (props) {
  return (
    {props.data}
}

class SecondComponent extends Component {
  constructor(props) {
    super(props);
    this.state = {
      // State object from the first component file
    }
  }
  render() {
    <DisplaySecondData data={this.state.myData} />
  }
}

Upvotes: 3

Views: 2212

Answers (3)

WebDeg Brian
WebDeg Brian

Reputation: 832

I am not really sure what you are trying to accomplish, but I would suggest 2 things:

  • Since <DisplayFirstData /> and <DisplaySecondData /> do the exact same things, you should move them to a new file and name it <DisplayData /> (I said 'it' because you will end up with only one component). Whenever you need it, just do: import DisplayData from 'path/to/file
  • Now you have the <DisplayData /> component, wrap a component round your <FirstComponent /> and <SecondComponent />, name it <ParentComponent />. Move all of the states from <FirstComponent /> to <ParentComponent />. If your data is fetched somewhere else, move the fetching code as well.

After that you just need to pass the states down to the <FirstComponent /> and <SecondComponent />. You can access the states directly as props in <SecondComponent /> or you can initialise the its states from props. For further info please read this

Overall, your code should look like:

import React, { Component } from 'react';
import { FirstComponent, SecondComponent } from 'path/to/folder/contains/the/files';

class ParentComponent extends Component {
  state = {
    //Move your states here
  }
  //Move your fetching code here
  render() {
    const { data } = this.state; 
    return(
      <>
        <FirstComponent data={data} />
        <SecondComponent data={data} />
      </>
    );
  }
}

And in <SecondComponent />:

import React from 'react';
import DisplayData from 'path/to/file';

export default SecondComponent = props => {
  const { data } = props.data;

  return(
    <DisplayData data={data} />
  )
}

Upvotes: 2

SakoBu
SakoBu

Reputation: 4011

As pointed out in the comments a common technique is to lift state up to the first common ancestor of both components and pass it down as props to both.

Here is your top level (Parent) component (A class-based component to keep your state) and then pass that data via props to the Children:

import DisplayFirstData from "./DisplayFirstData";
import DisplaySecondData from "./DisplaySecondData";

class App extends Component {
  state = { myData: "something" };
  render() {
    return (
      <div>
        <DisplayFirstData data={this.state.myData} />
        <DisplaySecondData data={this.state.myData} />
      </div>
    );
  }
}

In it, you pass the data that you have initialized in the state down to the second component that you are calling <DisplayFirstData /> via the prop data and the same for <DisplaySecondData />

And here is your child component 1:

const DisplayFirstData = props => (
  <div>
    <h2>Access your data here via props</h2>
    <p>{props.data}</p>
  </div>
);

export default DisplayFirstData;

And here is your child component 2:

const DisplaySecondtData = props => (
  <div>
    <h2>Access your data here via props</h2>
    <p>{props.data}</p>
  </div>
);

export default DisplaySecondData;

A working example on codesandbox... : https://codesandbox.io/s/407oq1znx

As a side note: I have no idea why you would need 2 different components that basically do the exact same thing but in any case, the example above is the way to do it... Also, in your learning journey, you should get to know and love the higher order component pattern and the context API (I suspect as you keep trying to build this you will need them...)

Upvotes: 0

Tholle
Tholle

Reputation: 112787

A common technique is to lift state up to the first common ancestor of both components, and pass it down as props to both.

Example

function getData() {
  return new Promise(resolve => setTimeout(() => resolve(42), 1000));
}

class FirstComponent extends React.Component {
  render() {
    return <div>{this.props.data}</div>;
  }
}

class SecondComponent extends React.Component {
  render() {
    return <div>{this.props.data}</div>;
  }
}

class App extends React.Component {
  state = { data: null };

  componentDidMount() {
    getData().then(data => {
      this.setState({ data });
    });
  }

  render() {
    const { data } = this.state;
    
    if (data === null) {
      return null;
    }
    return (
      <div>
        <FirstComponent data={data} />
        <SecondComponent data={data} />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Upvotes: 1

Related Questions