0

I'm trying to get values from a form component using props into the main App component where my state is. Using the values i get from the props, i want to update the main state. This is my code:

class App extends Component { state = { dataset: "", cc: "", cw: 0, ch: 0, bw: 0, bh: 0, xspacing: 0, yspacing: 0, barcolor: "", };

  // Function to use the data got from form component and setState
  dataForm = (
    dataset,
    canvascolor,
    canvaswidth,
    canvasheight,
    barwidth,
    barheight,
    xspacing,
    yspacing,
    barcolor
  ) => {
    this.setState({
      dataset,
      canvascolor,
      canvaswidth,
      canvasheight,
      barwidth,
      barheight,
      xspacing,
      yspacing,
      barcolor,
    });
    console.log(this.state);
  };

  render() {
    return (
      <div className="App">
        {/* This is the Form Component from where i'm getting my Data */}
        <DataForm dataForm={this.dataForm} />

        <DataGraph graph={this.state} />
      </div>
    );
  }
}

I am trying to send my updated state to the DataGraph component using props but it doesn't work, This is my DataGraph component code below:

class DataGraph extends Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }

  drawChart() {
    const d = this.props.graph.dataset.split`,`.map((x) => +x);
    const accessToRef = d3
      .select(this.myRef.current)
      .append("svg")
      .attr("width", this.props.graph.cw)
      .attr("height", this.props.graph.ch)
      .style("background-color", this.props.graph.cc);

    accessToRef
      .selectAll("rect")
      .data(d)
      .enter()
      .append("rect")
      .attr("x", (d, i) => i * this.props.graph.xspacing)
      .attr("y", (d, i) => this.props.graph.ch - this.props.graph.yspacing * d)
      .attr("width", this.props.graph.bw)
      .attr("height", (d, i) => d * this.props.graph.bh)
      .attr("fill", this.props.graph.barcolor);
  }

  componentDidMount() {
    this.drawChart();
  }

  render() {
    return (
      <>
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
          }}
          ref={this.myRef}
          className="pb-5"
        ></div>
      </>
    );
  }
}

DataGraph.propTypes = {
  graph: PropTypes.object.isRequired,
};

The setState() does not set the state values. Please help.

5
  • 1
    How did you verify that it doesn't set the state? Commented Jul 13, 2020 at 12:13
  • @FelixKling i have a graph that will be initialized and displayed using the values in the state. Since that doesn't pop-up, i can verify that the state doesn't change. Commented Jul 13, 2020 at 12:16
  • 1
    Well, the first thing I would do is check whether the dataForm function is called at all, since this is where you are calling setState in. Then i would read up on the documentation of DataForm (I assume that's not one of your own components) to see how it should be used and what data it passed to callbacks. Also note that some of the properties you pass to setState don't exist in your component's state. Not sure whether that's relevant or not since we also don't know what DataTable is or does. Commented Jul 13, 2020 at 12:18
  • @FelixKling the state changes properly. The problem now is that i want to pass this changed state to another component using props, but that isn't happening. Help ? Commented Jul 13, 2020 at 12:21
  • If you think state management is becoming more complex in your react-app the use react-redux Commented Jul 13, 2020 at 12:45

3 Answers 3

1

the state is changing the problem is that the setState is an async task so you have to wait till its end and to verify that your state is updating try the code below:-

dataForm = (
dataset,
canvascolor,
canvaswidth,
canvasheight,
barwidth,
barheight,
xspacing,
yspacing,
barcolor
) => {
this.setState({
  dataset,
  canvascolor,
  canvaswidth,
  canvasheight,
  barwidth,
  barheight,
  xspacing,
  yspacing,
  barcolor,
},()=>{
  console.log(this.state);
});

};

setState returns the callback after its finish its task you can use it to sync the setState function

to update the data in the child component when the state of the parent component changes you have to use the props like in below example

const ExampleComponent =(props) =>{
  return <div>
             <Text>{{props.text}}</Text>
         </div>
}

and pass the props in a component like this

<ExampleComponent text={this.state.text} />

now whenever you change the value of the text in the state it will reflect in your child component.

Sign up to request clarification or add additional context in comments.

8 Comments

Thankyou. I have verified that the state changes. But i want to pass this state to another component using props as shown in <DataGraph graph={this.state} /> but this doesn't work. Help ?
you have to use the props {graph} directly in your component like (this.props.graph) or without this depending on your component type. by which whenever the value of your props which is stored in the states changes it will also reflect on your component
could you maybe write a small example ?
ya sure just give me the sample of your DataGraph component i will show you an example
@MushoodHanif i updated the answer below with an example feel free to explore\
|
0

the main problem due to which your component is not reloading is due to you uses the props when component mounted itself and when you update the state it does not reflect in the child component

to solve this you have to use the react life cycle hook called componentWillReceiveProps

like this

  componentWillReceiveProps() {
    this.drawChart();
  }

you also have to add this lifecycle hook in your component so that whenever your props get updated it recall the function and reflect the changes

5 Comments

should i replace the componentDidMount() with this ?
no write both componentDidMount is for when you load it the first time and componentWillReceiveProps when props update
@MushoodHanif does it helps you
I did the following change in my DataGraph: componentDidMount() { this.drawChart(); } componentWillReceiveProps() { this.drawChart(); } This doesn't work. Am i doing it right ?
Thankyou for the solution brother. I've done it. The solution was to use the getDerivedStateFromProps() to get the props from the parent component and put it in the child component's state. Your method works in a similar way but is now deprecated, but it led me to the solution. Thankyou again.
0

The Solution is to use the getDerivedStateFromProps() Static Method to get the State from the Parent component as props and use those props to initialize the child component's state. Here is the Code:

Passing Parent Component State as Props to Child Component:

<DataGraph graph={this.state} />

Using the Above Mentioned Method to Update the Child Component State:

class DataGraph extends Component {
  constructor() {
    super();
    this.state = {
      dataset: "",
      cc: "",
      cw: 0,
      ch: 0,
      bw: 0,
      bh: 0,
      xspacing: 0,
      yspacing: 0,
      barcolor: "",
    };
    this.myRef = React.createRef();
  }

  static getDerivedStateFromProps(props, state) {
    return {
      dataset: props.graph.dataset,
      cc: props.graph.cc,
      cw: props.graph.cw,
      ch: props.graph.ch,
      bw: props.graph.bw,
      bh: props.graph.bh,
      xspacing: props.graph.xspacing,
      yspacing: props.graph.yspacing,
      barcolor: props.graph.barcolor,
    };
  }

  drawChart() {
    const d = this.state.dataset.split`,`.map((x) => +x);
    const accessToRef = d3
      .select(this.myRef.current)
      .append("svg")
      .attr("width", this.state.cw)
      .attr("height", this.state.ch)
      .style("background-color", this.state.cc);

    accessToRef
      .selectAll("rect")
      .data(d)
      .enter()
      .append("rect")
      .attr("x", (d, i) => i * this.state.xspacing)
      .attr("y", (d, i) => this.state.ch - this.state.yspacing * d)
      .attr("width", this.state.bw)
      .attr("height", (d, i) => d * this.state.bh)
      .attr("fill", this.state.barcolor);
  }

  render() {
    this.drawChart();
    return (
      <>
        <div
          style={{
            display: "flex",
            justifyContent: "center",
            alignItems: "center",
          }}
          ref={this.myRef}
          className="pb-5"
        ></div>
      </>
    );
  }
}
The getDerivedStateFromProps() is a Static Method as Mentioned Above, so Keep that in Mind While using it. Also, do not initialize "props" in the constructor() or the super() otherwise it won't work. Thankgod it worked, I hate Redux Boilerplate 😅.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.