- Now that we preload the initial data through the initial server
- request, we can clean up the async code that we have here in the App component.
- We don't need the componentDidMount, we don't need axios, and we don't need DataApi.
- Much cleaner. In fact, we can actually not use a state object at all.
- We're not changing the state, so we can totally get rid of the state
- object here if we want at this point, but I'm going to keep it because
- soon we'll introduce an action that changes this state, and we will do
- that through the external state manager that we started under the state-api package.
- So far, we've been using individual methods in the state-api package
- to structure the App state, but it would be ideal if the state-api
- package was responsible for the whole state object and we just always
- read it from there. So, instead of specifying articles and authors
- here, we just specify a data store and always read the state of the
- application from that store. So that is exactly what I'm going to do
- right now. I'm going to get rid of this initialData object.
- And this DataApi variable, I'm going to rename it to StateApi just for consistency.
- And I'm going to call this store, not just an API.
- So, it's exactly the same thing, but I'm going to add responsibilities
- to this store. So, every time we create a new object from the
- state-api, we get back a store that manages everything about the data.
- And in here, instead of passing initialData, I'm going to pass the
- store object, just like that. So my app only cares about the store object.
- I don't have initialData here anymore, but I'm going to keep an
- initialData concept and just pass the rawData in here.
- Okay, so things will not work yet, because I need to do some changes
- on the client side as well. So let's take a look at the client side.
- So the client side will now have an initialData, but it's actually the
- rawData, so the client side will need to do exactly the same steps.
- We need to initialize the store object, so in this case it will be
- store equal new StateApi, but this time we're reading the rawData from
- the window object, window.initialData, and I need to pass this store
- object just like I did server side. Store is store.
- And I also need the state-api package. So now, let's go back to the App component.
- Instead of manually structuring the state of the application here,
- we can now read it from the store object, which we're passing here as a prop.
- So the store object is available here as this.props.store,
- and I'll just assume that this store object will have a getState
- method that returns the whole state. So that's all the changes that I
- need to do in the App component. Now, let's go to the state-api package.
- So under index here, keep in mind that we use that with getState.
- So in here I'm going to go ahead and expose a getState method,
- and inside getState I can return an object to represent both the
- articles, which I can read from this.getArticles, and the authors,
- which I can read from this.getAuthors here.
- And things will actually work at this point.
- In fact, let's test that and see where we are.
- Things are working just fine, both the server side and the client-side
- rendering correctly without any warnings from React.
- However, if I'm going to read this state multiple times,
- this means that I'm going to be returning this object and basically
- doing the conversion that I do inside getArticles and getAuthors every
- time I read the state. So that's actually not ideal.
- So let's fix that. Instead of managing rawData here, I'm going to go
- ahead and manage this.data, the actual data object that I'm going to expose.
- And this data object will have articles and I'll compute the value of
- these articles right here inside the constructor,
- so this .mapIntoObject from rawData.articles.
- I'll do exactly the same for the authors property, so authors to be
- computed from inside the map into object.
- This means I don't really need to expose getArticles and getAuthors
- object now, because I'm always exposing getState method,
- and the getState method can simply return this.data.
- So, what we have is equivalent, but now every time I read the state,
- I'm reading the exact same variable and I'm not doing the computation every time.
- I think this is better. Make sure things are still rendering,
- and they are. Let me rename this into state-api again for consistency.
- And now since I have a state-api object that manages the state of the
- application, I can always read from there.
- So, for example, in the App component, I previously had a lookupAuthor
- object that I had to pass down to the Article component to look up an author.
- But now I can do this thing inside my state manager, so I'm going to
- kill this part here, I don't need it anymore, and inside the state-api,
- we can define lookupAuthor directly here. So this is going to take an
- authorId, and it will simply return this.data.authors for the passed-in authorId.
- So exactly the same logic, but now inside this state-api.
- Let me actually change those into class properties so that we don't
- have to deal with any binding. So getState is a Class Property here
- and it's using Arrow functions. So now if we go back to the App
- component, I don't need to pass articleActions down to the Article component.
- Instead, I can pass the store itself, because I have the look up
- author defined on the store itself. So look how much we're
- simplifying this App component now. Instead of articleActions,
- I'm going to pass store, which is part of the props of the component here.
- So this.props.store. And in articleList I need to do the same.
- Instead of passing actions, I'll just pass the store itself,
- so the store is now a property here, store, and inside the Article
- component, instead of reading the actions here, I'm going to go ahead
- and read the store. And the lookup author is part of the store API,
- just like that. And I think this should work as well, and it is working.
- It's rendering both server-side and client-side exactly the same,
- but now I have one manager of this state, this state API class from
- which I created the store object, and it manages the state.
- It manages the initial shape of the state, it manages any functions I
- need from that state. That made my React application much simpler.
- The React application depends on the store for reading the initial state.
- It also depends on the store for passing down some actions all the way
- to the Article component and looking up the author from this store here directly.
- However, to get this to work, I had to pass the store object to all
- the components, including this ArticleList component, which really did
- not care about the store. What do you think we can do to make that better?
- How can we make the Article component access the store,
- because it needs to, but without having the ArticleList component pass
- the store as a prop? Because again, the ArticleList component does
- not really need to be even aware of the existence of a store object.
- Think about that, and in the next module we'll talk about it.
- But before we go there, I think the changes that we made here probably
- broke the few tests that we have. Let's fix those.
- The first test is in the snapshot of the ArticleList component.
- Previously, we had article actions, now we have store,
- and it's actually the exact same signature.
- And the other failing tests is for the DataApi itself.
- So let's take a look at that and their tests DataApi.
- We are still reading getArticles here, so I'm going to go ahead and
- rename this as state-api for consistency, and I'll rename this as store.
- Now, instead of getArticles, I need to do getState, which is a
- function, and then read the articles from there.
- And same thing for the authors. Instead of getAuthors I need to do to
- getState, and then read the authors from there. So that should make them pass.