Learn how to avoid the boilerplate of passing the props down the intermediate components by introducing more container components.
If the parent component does not update when the store updates, then FilterLink will re-render with a stale value
It's probably a mistake on my part to wrap my head around this without hands on experience, but I do have a question: When would not updating the parent component, be of consequence to the FilterLink (a child component)? Can you please give me an example?
Up to this point the tutorial is excellent, but I have a problem with this lesson. The FilterLink component in this lesson is not following the rules in React. This error is removed in later chapters and is not the way things are done in Redux, so it is just confusing. And it is not needed in order to get an understanding of how things are done in Redux either.
Let me explain the problem:
The contract of a a react component is that the result returned from render should only depend on this.state and this.props and nothing else. See the component spec
In this lesson we have for FilterLink
render() {
const state = store.getState()
and then state.visibilityFilter() is used when setting up the returned Link element. That is, render() depends on something else than this.state or this.props which is simply illegal in React.
The proper way to do this is to use this.state instead. This is done by reading the value from store.getState() in the subscribe listener and call this.setState() of the component.
componentDidMount() {
this.unsubscribe = store.subscribe(() =>
this.setState({visibilityFilter: store.getState().visibilityFilter});
...
render() {
const state = this.state; // NB No access of store here!
When done this way the forceUpdate call is not needed, since re-rendering will be triggered properly through setState.
Here is an [example] (http://jsbin.com/kuboqi/edit?html,js,output) where the parent component gets re-rendered but the children don't. In essence this depends on the optimizations in the implementation of React rendering. It assumes the components follow the contract: if props and state are unchanged render should return the same thing, so calls to render can be optimized away. Exactly how this is done is an implementation detail and not specified. But it's not a problem: as long as your components follow the contract they will be re-rendered properly. (Then, if you don't break things, you don't need to worry how to fix it again)
[Here] (https://github.com/facebook/react/issues/4067) is a discussion where Sebastian Markbåge make some good clarifications on this topic.
This tutorial is just an approximation of how connect() from React Redux works. Please watch series to the end, which is where we start using it and remove the “wrong” code. Technically connect() uses setState() but this is irrelevant implementation detail to this tutorial which is why I went with forceUpdate(). It really doesn't matter because this code is temporary and is later changes to use connect() instead.
I'm confused about the use of props.filter
here. It seems like filter
should be an explicitly defined argument to the FilterLink "constructor", instead it's not explicitly defined as a required property but it is implicitly relied upon. How are users of FilterLink
to know which props they should set on it, which it supports and which are required?
I'd love to see this intermediate impl (using react state) between the quick-and-dirty impl here and the final black-box connect
impl. Lars's comment mostly covers it I guess :)
How are users of FilterLink to know which props they should set on it, which it supports and which are required?
Usually people define propTypes
on the component. They serve as a kind of documentation. You can define propTypes
on the component returned by connect()
too.
I'd love to see this intermediate impl (using react state) between the quick-and-dirty impl here and the final black-box connect impl. Lars's comment mostly covers it I guess :)
I tried it at first but it made things super confusing because the word “state” now refers to completely different things: React state (an implementation detail) and Redux state (the thing we’re trying to teach). It’s so easy to confuse one for the other so I decided not to mention React state at all, especially considering that this hack is going away in the next lessons.
In my Moz FF49 browser FilterLink is re-rendered anyway along just as the rest of the application, componentDidMount and componentWillUnmount do not get called at all. So I'm not sure I understand your point - why use componentDidMount at all?
Is this just a place to explain updates between Redux store and React?
I didn't see any difference of using the below code. For me it worked same with or without.
componentDidMount(){
this.unsubscribe = store.subscribe(() => {
this.forceUpdate();
});
}
componentWillUnmount(){
this.unsubscribe();
}
as far as i understand it ...
in this lesson, dan reminds us that the entire app is subscribed to the store with the line store.subscribe( render )
. because any change in the app will update all components the FilterLink code change doesn’t create any noticeable change - thus you can comment out the componentDidMount
and componentWillUnmount
without any change in how the application works.
but this lesson only begins the process of extracting the components, so if you comment out the subscription, store.subscribe( render )
, it will break the app - partially. the FilterLink will continue to work, but adding todos will not.
in the next lesson, dan finishes the component extraction and is then able to remove the store.subscribe( render )
. each container component subscribes itself, individually, to the store so the app, as a whole, no longer needs to subscribe to the store. if you comment out the componentDidMount
lines at that point, then you’ll see the “stale” state that he mentions in this video.