简体   繁体   中英

React child chart component doesn't get updated

I'm new to React and trying to figure out how props and states are work. I've think of a simple application which uses states and props. It has three buttons for increasing and decreasing numbers. It actually works and updates the numbers. I also wanted to a chart component to see the change of the numbers. But React doesn't update the chart.

My App.js is;

import React from "react"
import ChartComponent from './Chart'


class App extends React.Component {
  constructor() {
    super()
    this.state = {
      count: 12,
      data: [{ count: 12 }, { count: 13 }, { count: 169 }]
    }
    this.linearIncrease = this.linearIncrease.bind(this)
    this.parabolicIncrease = this.parabolicIncrease.bind(this)
    this.parabolicDecrease = this.parabolicDecrease.bind(this)
  }

  linearIncrease() {
    this.setState(previousState => {
      let prevState = previousState.data;
      prevState.push({ count: previousState.count + 1 })
      return {
        count: previousState.count + 1,
        data: prevState
      }
    })
  }

  parabolicIncrease() {
    this.setState(previousState => {
      let prevState = previousState.data;
      prevState.push({ count: previousState.count * previousState.count })
      return {
        count: previousState.count * previousState.count,
        data: prevState
      }
    })
  }

  parabolicDecrease() {
    this.setState(previousState => {
      let prevState = previousState.data;
      prevState.push({ count: Math.sqrt(previousState.count) });
      return {
        count: Math.sqrt(previousState.count),
        data: prevState
      }
    })
  }

  render() {
    return (
      <div>
        <h1>{this.state.count}</h1>
        <button onClick={this.linearIncrease}>Linear Increase!</button>
        <button onClick={this.parabolicIncrease}>Parabolic Increase</button>
        <button onClick={this.parabolicDecrease}>Parabolic Decrease</button>
        <ChartComponent data={this.state.data}></ChartComponent>
      </div>
    )
  }
}

export default App

Chart.js file;

import React from 'react'
import {
    LineChart, Line
} from 'recharts';


const ChartComponent = (props) => {
    return (
        <div>
            <LineChart width={300} height={100} data={props.data} >
                <Line type='monotone' dataKey='count' stroke='#8884d8' strokeWidth={2} />
            </LineChart>
        </div>
    )
}

export default ChartComponent

Even though React update count you are still mutating this.state.data using push .

React re-render only when the reference to the state changes, If you check this.state.data === prevState.data you will get true because they are the same object reference. That's why Chart doesn't re-render because React doesn't tell Chart that data has changed.

It is better to always create a new object and then mutate it like so, Also because objects are mutable in JavaScript you can create them using const, this will still allow you to mutate the object but will not let you reassign a new value to the variable.

const prevStateData = [...previousState.data];

I would also suggest to create a general function which will take a function as the operation and update and state, this will make the code a lot more readable and simple

createOperation(fn) {
  return () => {
    this.setState(prevState => {
      const count = fn(prevState.count);
      return {
        count,
        data: [...prevState.data, { count }]
      };
    });
  };
}

Then you can define your functions like so

linearIncrease(count) {
  return count + 1;
}

parabolicIncrease(count) {
  return count * count;
}

parabolicDecrease(count) {
  return Math.sqrt(count);
}

And using them

<button onClick={this.createOperation(this.linearIncrease)}>
  Linear Increase!
</button>
<button onClick={this.createOperation(this.parabolicIncrease)}>
  Parabolic Increase
</button>
<button onClick={this.createOperation(this.parabolicDecrease)}>
  Parabolic Decrease
</button>

sandbox

I updated the linearIncrease logic to make it work:

linearIncrease() {
  this.setState(previousState => {
    return {
      // ...previousState,
      count: previousState.count + 1,
      data: [...previousState.data, {count: previousState.count + 1}],
    }
  })
}

The source code under the question updates the count but it doesn't modify data object. React compares the props and it doesn't update the chart component because there is no change to apply. (Chart wouldn't change even if the component was updated because the change is not presented in the data object)

Here is the working button and the source code: https://stackblitz.com/edit/react-chart-state

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM