How to compare props in ComponentDidUpdate for large data structure connected with Redux

Viewed 7231

I've been working with new lifecycles of React v16. It works great when we compare only a single key. But when it comes to compare a large data structures like an Arrays of objects, the deep comparison will become very costly.

I have use case like this in which I have an array ob objects stored in redux,

const readings =[
{
id: ...,
name: ...',
unit:...,
value: ...,
timestamp: ...,
active: true,
 },
 ...
]

Whenever active state of any objects get changed I dispatch an action to update redux state to be same for all connected components with that reducer.

class Readings extends Component {
  state = {
    readings:[],
  };

  static getDerivedStateFromProps(nextProps, prevState) {
    if ( // comparsion of readings array with prevState) {
      return {
        readings: nextProps.readings,
      };
    }
    return null;
  }

  componentDidUpdate(prevProps) {
    if ( // comparsion of readings array with prevState) {
      // perform an operation here to manipulate new props and setState to re render the comp
      // this causes infinite loop
    }
  }

  render() {
   ...
  }
}

const mapStateToProps = state => ({
  readings: state.readings.readings,
});


export default connect(
  mapStateToProps,
)(Readings));

How can I avoid infinite loop on setState in componentDidUpdate, I don't want to do deep comparison of readings array. Is there a better solution to handle this case?

Your suggestions will be highly appreciated.

2 Answers

Ideally, you make immutable changes to your reducer and keep the reducer state level low.

So if your array consists of many objects and you need to dispatch based on some attribute change, you should replace the whole readings array using spread operator or using some immutable library e.g immutablejs. Then in your componentDidupdate you can have something like :

componentDidUpdate(prevProps) {
   const {
     readings,
   } = this.props
   const {
     readings: prevReadings,
   } = prevProps
  if (readings !== prevReadings) {
      //dispatch something
  }
}

Thanks feedbacks are welcome.

First read another answer, If that didn't work for you, then:

  1. Make sure you're comparing two arrays with :
componentDidUpdate(prevProps){
  if(JSON.stringify(prevProps.todos) !== JSON.stringify(this.props.todos){...}
}
  1. Make sure you are changing the passed prop (state in parent) after deep cloning it:
let newtodos = JSON.parse(JSON.stringify(this.state.todos));
newtodos[0].text = 'changed text';
this.setState({ todos : newtodos });

(Note that Shallow clone doesn't work, since that way you change the objects directly)

Related