The core idea of React to turn the imperative management of data in an application into a declarative one. The best way to stick this philosophy is to consistently think about how to define behavior as function of props and state. Here is an example:
Say you have a time tracking Show archive.org snapshot component, to view the elapsed time and to switch to a different tracking; either resume and old one of start a new one (NEXT).(see below)
We would like for the current tracking to be automatically saved when we navigate to new or old tracking.
The obvious way to implement this would be to have a method on the main component that looks something like this:
navigateToTracking: function(newTrackingId){
if (this.hasUnsavedChanges())
this._saveChanges();
}
this.setState({
currentTrackingId: newTrackingId
})
}
This setup has one major shortcoming though. We have to make sure that the click handlers for the NEXT
, PREVIOUS
and RESUME
button all invoke the navigateToTracking
method rather than directly setting the currentContactId
state.
This is clearly an imperative approach, where the top level component acts more like a controller in Rails or a main method. It also increasing the coupling between components and reduces their composability.
Let us instead declare what it is that we want to happen using componentDidUpdate
: when the currentTrackingId changes save unsaved changes.
componentDidUpdate: function(prevProps, prevState) {
if (prevState.currentTrackingId !== state.currentTrackingId) {
if (this._hasUnsavedChanges()) {
this._saveChanges();
}
}
}
Here we hook into the component's life cycle and make the functionality to save the current tracking purely a function of its state. This is much harder to break since event handlers in the 'outside' world can now simply call this.setState
instead of having to know about the components need to save its current state.
PS: I read about this in an article I cannot find right now, if anyone comes across it, please add it to this card