2

I have a ReactJS project where i get JSON from REST Django host and creating a table with filters for it. I have a Table class :

class MainTable extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      results: []
    };
  }

  componentDidMount(){
    axios.get(this.props.link)
      .then(res => {
        this.setState({results: res.data.results});
    });
  }

  render() {
    return (
      <Table hover striped bordered responsive size="sm">
        <thead>
          <tr>
            <th>Name</th>
            <th>Name</th>
          </tr>
        </thead>
        <tbody>
          {this.state.results.map(result =>
            <tr key={result.fileId}>
              <td>{result.Name}</td>
              <td>{result.Name}</td>
            </tr>
          )}
        </tbody>
      </Table>
    );
  }
}

And Main where i run all filter classes :

class Main extends React.Component {
  constructor() {
    super();
    this.state = {
      origin: '',
      limit: 10
    };

    this.handleChangeOrigin = this.handleChangeOrigin.bind(this);
    this.handleChangeLimit = this.handleChangeLimit.bind(this);
  }

  handleChangeLimit(event) {
    this.setState({limit: event.target.value});
  }
  handleChangeOrigin(event) {
    this.setState({origin: event.target.value});
  }

  render() {
    var link = `http://106.120.89.142:8000/database/?limit=${this.state.limit}&`;
    if (this.state.origin){
      link += `ORIGIN=${this.state.origin.toLowerCase()}`;
      console.log(link)
    }
    return (
      <div>
        <div>
          <h1 className="jumbotron-heading display-4">Here u got database *_*</h1>
        </div>
        <div>
          <Limit handleChange = {this.handleChangeLimit} />
        </div>
        <div>
          <OriginRow handleChange = {this.handleChangeOrigin} />
        </div>
        <div id="tableWrapper">
          <MainTable link={link} />
        </div>
      </div>
    );
  }
}

And i have a problem with it, cause when i use componentDidMount(), my axios.get(my link to REST JSON) runs only once. When i use axios in Table class render(), it hits my server few times per second. Can i make mounting only when my props to Table class changed?

Chris
  • 57,622
  • 19
  • 111
  • 137
Alex
  • 1,221
  • 2
  • 26
  • 42
  • *"Can i make mounting only when my props to Table class changed?"* - do you mean the `TableMain` component? Because `Table` is a react-bootsrap component. – Chris Jul 07 '17 at 12:13
  • `MainTable class`, exactly. Sorry, I could be more precise. – Alex Jul 07 '17 at 12:27

3 Answers3

4

As pointed out you can implement shouldComponentUpdate. Alternatively if you dont need a deep comparison, ie on any collections or objects, just use PureComponent instead of Component:

https://github.com/facebook/react/blob/master/docs/docs/reference-react.md

React.PureComponent# React.PureComponent is exactly like React.Component but implements shouldComponentUpdate() with a shallow prop and state comparison.

terpinmd
  • 1,014
  • 8
  • 15
1

Thanks for help, the best solution I found and choose is :

  componentDidMount() {
    axios.get(this.props.link)
      .then(res => {
        this.setState({results: res.data.results, count: res.data.count});
    });
  }

  componentWillReceiveProps(nextProps) {
    axios.get(nextProps.link)
      .then(res => {
        this.setState({results: res.data.results, count: res.data.count});
    });
  }

It's exactly what I need, you can read about it here: https://facebook.github.io/react/docs/react-component.html#componentwillreceiveprops. It rerun my render() every time I get new props and I didn't use axios in my render, which is more attractive.

Alex
  • 1,221
  • 2
  • 26
  • 42
0

You should take a look at the shouldComponentUpdate() life-cycle method, here.

shouldComponentUpdate()

shouldComponentUpdate(nextProps, nextState)

Use shouldComponentUpdate() to let React know if a component's output is not affected by the current change in state or props. The default behavior is to re-render on every state change, and in the vast majority of cases you should rely on the default behavior.

shouldComponentUpdate() is invoked before rendering when new props or state are being received. Defaults to true. This method is not called for the initial render or when forceUpdate() is used.


Add the following snippet to your MainTable component. This will prevent it from re-rendering, unless the props have changed.

shouldComponentUpdate(nextProps) {
  return JSON.stringify(this.props) !== JSON.stringify(nextProps);
}

this will check for all props. If you want to check against a specific prop, you can do:

shouldComponentUpdate(nextProps) {
  return JSON.stringify(this.props.link) !== JSON.stringify(nextProps.link);
}

As pointed out in the comments, there is always a small chance that JSON.stringify(this.props) !== JSON.stringify(nextProps) will return false even when they are equal.

As such, if you want a more robust way of comparing the this.props object to the newProps object, you should take a look at this post.

Community
  • 1
  • 1
Chris
  • 57,622
  • 19
  • 111
  • 137
  • `JSON.stringify` is not stable in the order of the keys, so this introduces a bug. At least a bug which, in this case, will usually result in a re-render where it wouldn't have been wanted. – Ingo Bürk Jul 07 '17 at 12:37
  • Thank u so much, but one more question. How to run my `MainTable` on start, I got an ampty `Table` before filtering now, and i want to get all the database there as before. – Alex Jul 07 '17 at 12:38
  • Objects in JavaScript aren't ordered and stringify doesn't order them either, so you're just relying on undefined behavior. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify – Ingo Bürk Jul 07 '17 at 15:36