The application is cleaner, but now has that bug of infinite redirecting. You will first fix that.
In the App component, it would change state in response to the LoginPanel calling the updateToken method. The LoginPanel no longer does that because it dispatches its information to a thunk that makes the AJAX call and, in turns, dispatches an action that updates the Redux store. Then, LoginPanel uses the value from the store to no that something good has happened. You need to have App do the same.
Since updateToken is no longer used, remove the method and all of its uses from the App component.
When you have that done, you may notice that the route that shows the LoginPanel looks like this.
That is rendering LoginPanel and passing its props to it. That’s just like using the “component” property of the Route component, so change it to use that instead of the more expensive “render” property.
You’re still in a render loop, so that hasn’t fixed it. Time to connect App to the Redux store.
LoginPanel, import the connect function from the “react-redux” module.LoginPanel, declare mapStateToProps and mapDispatchToProps functions after the component.mapStateToProps function, map the token to a property named “token” identically to the way it is done in LoginPanel.mapDispatchToProps just returning an empty object.App to the Redux store using those functions.That puts the value of the token into the props. In the actual App component, now find everywhere that uses this.state.token and replace it with this.props.token.
Try logging in, again. Still doesn’t work. That’s because App relies on another setting in its state named “needLogin” which is just a Boolean value that is basically the opposite of whether the token has a value. If there is a token, there is no need to login. If there is no token, there is a need to login. You can figure that out in the mapStateToProps function! Create another property, one named “needLogin”, in the object returned from the function. If there is a value in state.authentication.token, then set it to false. If there is no value (or an empty string) in state.authentication.token, then set “needLogin” to true. Once you have that, find every use of this.state.needLogin and replace it with this.props.needLogin.
You have now fixed the problem with the infinite redirects! And, once you log into the application, you can check that the App component is rendering the PokemonBrowser component. However, it is not showing anything. That’s because the App component calls its loadPokemon method in the componentDidMount method. There’s no token at that time in its state because the token now comes from Redux.
What would be great is if, after logging in, the login action loaded the Pokemon for you, put them in the store, and PokemonBrowser could just use them directly.
Oh, that’s what you’ll do next.
Now, you need some actions, thunks, and reducers for Pokemon, not authentication. Create a new file src/store/pokemon.js. In there, create the following items.
LOAD with a value of ‘pokedex/pokemon/LOAD’load that takes in a list of Pokemon and creates an action with the type of LOAD and the list of Pokemon in itstate parameterNow, you need to make a thunk that will make the AJAX call. Call your think “getPokemon”. The thunk needs the token from the state to make its API call. The function that gets the “dispatch” parameter can also get a second parameter, a function conventionally called “getState”. Your thunk could look like this.
export const getPokemon = () => async (dispatch, getState) => {
const { authentication: { token } } = getState();
// AJAX call
// Handle response
};Then, in configureStore.js, import the default reducer and add it to the combineReducers argument as the “pokemon” property next to “authentication”.
Now, you just need to kick off that AJAX call. It seems only reasonable that the component that actually needs it kicks it off, the PokemonBrowser component. In PokemonBrowser, do the following:
connect function from “react-redux”getPokemon thunk you just createdmapStateToProps function that maps the list of Pokemon from state.pokemon.list (or whatever you called your property in the reducer) to a property named “pokemon”mapDispatchToProps function that returns an object with a property named “getPokemon” that dispatches the getPokemon thunk you importedconnect, mapStateToProps, and mapDispatchToPropscomponentDidMount method to the PokemonBrowser component and call this.props.getPokemon() from itNow, when you log into the application, you should see two actions in your Redux store!

More importantly, you should see the list of Pokemon in the PokemonBrowser actually appear in the browser.
Previously, all of the fetching logic for the list of Pokemon was handled by the App component. You can now get rid of the loadPokemon method and clean up any calls to it. Also, anywhere that refers to this.state.pokemon or using setState to update the “pokemon” property, you should get rid of all of that. This makes the handleCreated method empty, so get rid of that and all references to it, too, in the App component.
Because the App component doesn’t make any AJAX calls, anymore, it doesn’t need the token from the state. Remove the “token” property in mapStateToProps and everywhere token is used in the App component. Include the call to local storage, too, in the deleting of things. You can remove the import of baseUrl, too, because there are no AJAX calls in the file.
Now, because cProps in the render method is empty, delete it and its uses in the PrivateRoute components below it. Now that the code is not using cProps, you can delete the parameter and its use from the PrivateRoute component on line 8 (or so) of the src/App.js file.
Actions that use outside resources like AJAX calls and local storage must be created in thunks. Back in the src/store/authentication.js module, do two things:
TOKEN_KEY and set it equal to some non-empty stringlogin thunk, between getting the token from the response and dispatching the setToken action, write the token to local storage using the constant TOKEN_KEYYou need a new thunk to do this. Create a thunk named loadToken that takes no parameters, and returns a function that accepts a “dispatch” parameter. Then, implement it to read the value from local storage using the TOKEN_KEY constant. If a value comes back, have it dispatch the setToken action.
In the App component, import the loadToken thunk. Use it in the mapDispatchToProps by mapping the dispatch of the loadToken thunk to a property of the same name.
Invoke that loadToken method in the componentDidMount method of the App component.
The moment you do that, the page should refresh and you should see the Pokemon browser rather than the login form.
You’re halfway home!
The application is cleaner, but now has that bug of infinite redirecting. You will first fix that.
In the App component, it would change state in response to the LoginPanel calling the updateToken method. The LoginPanel no longer does that because it dispatches its information to a thunk that makes the AJAX call and, in turns, dispatches an action that updates the Redux store. Then, LoginPanel uses the value from the store to no that something good has happened. You need to have App do the same.
Since updateToken is no longer used, remove the method and all of its uses from the App component.
When you have that done, you may notice that the route that shows the LoginPanel looks like this.
That is rendering LoginPanel and passing its props to it. That’s just like using the “component” property of the Route component, so change it to use that instead of the more expensive “render” property.
You’re still in a render loop, so that hasn’t fixed it. Time to connect App to the Redux store.
LoginPanel, import the connect function from the “react-redux” module.LoginPanel, declare mapStateToProps and mapDispatchToProps functions after the component.mapStateToProps function, map the token to a property named “token” identically to the way it is done in LoginPanel.mapDispatchToProps just returning an empty object.App to the Redux store using those functions.That puts the value of the token into the props. In the actual App component, now find everywhere that uses this.state.token and replace it with this.props.token.
Try logging in, again. Still doesn’t work. That’s because App relies on another setting in its state named “needLogin” which is just a Boolean value that is basically the opposite of whether the token has a value. If there is a token, there is no need to login. If there is no token, there is a need to login. You can figure that out in the mapStateToProps function! Create another property, one named “needLogin”, in the object returned from the function. If there is a value in state.authentication.token, then set it to false. If there is no value (or an empty string) in state.authentication.token, then set “needLogin” to true. Once you have that, find every use of this.state.needLogin and replace it with this.props.needLogin.
You have now fixed the problem with the infinite redirects! And, once you log into the application, you can check that the App component is rendering the PokemonBrowser component. However, it is not showing anything. That’s because the App component calls its loadPokemon method in the componentDidMount method. There’s no token at that time in its state because the token now comes from Redux.
What would be great is if, after logging in, the login action loaded the Pokemon for you, put them in the store, and PokemonBrowser could just use them directly.
Oh, that’s what you’ll do next.
Now, you need some actions, thunks, and reducers for Pokemon, not authentication. Create a new file src/store/pokemon.js. In there, create the following items.
LOAD with a value of ‘pokedex/pokemon/LOAD’load that takes in a list of Pokemon and creates an action with the type of LOAD and the list of Pokemon in itstate parameterNow, you need to make a thunk that will make the AJAX call. Call your think “getPokemon”. The thunk needs the token from the state to make its API call. The function that gets the “dispatch” parameter can also get a second parameter, a function conventionally called “getState”. Your thunk could look like this.
export const getPokemon = () => async (dispatch, getState) => {
const { authentication: { token } } = getState();
// AJAX call
// Handle response
};Then, in configureStore.js, import the default reducer and add it to the combineReducers argument as the “pokemon” property next to “authentication”.
Now, you just need to kick off that AJAX call. It seems only reasonable that the component that actually needs it kicks it off, the PokemonBrowser component. In PokemonBrowser, do the following:
connect function from “react-redux”getPokemon thunk you just createdmapStateToProps function that maps the list of Pokemon from state.pokemon.list (or whatever you called your property in the reducer) to a property named “pokemon”mapDispatchToProps function that returns an object with a property named “getPokemon” that dispatches the getPokemon thunk you importedconnect, mapStateToProps, and mapDispatchToPropscomponentDidMount method to the PokemonBrowser component and call this.props.getPokemon() from itNow, when you log into the application, you should see two actions in your Redux store!

More importantly, you should see the list of Pokemon in the PokemonBrowser actually appear in the browser.
Previously, all of the fetching logic for the list of Pokemon was handled by the App component. You can now get rid of the loadPokemon method and clean up any calls to it. Also, anywhere that refers to this.state.pokemon or using setState to update the “pokemon” property, you should get rid of all of that. This makes the handleCreated method empty, so get rid of that and all references to it, too, in the App component.
Because the App component doesn’t make any AJAX calls, anymore, it doesn’t need the token from the state. Remove the “token” property in mapStateToProps and everywhere token is used in the App component. Include the call to local storage, too, in the deleting of things. You can remove the import of baseUrl, too, because there are no AJAX calls in the file.
Now, because cProps in the render method is empty, delete it and its uses in the PrivateRoute components below it. Now that the code is not using cProps, you can delete the parameter and its use from the PrivateRoute component on line 8 (or so) of the src/App.js file.
Actions that use outside resources like AJAX calls and local storage must be created in thunks. Back in the src/store/authentication.js module, do two things:
TOKEN_KEY and set it equal to some non-empty stringlogin thunk, between getting the token from the response and dispatching the setToken action, write the token to local storage using the constant TOKEN_KEYYou need a new thunk to do this. Create a thunk named loadToken that takes no parameters, and returns a function that accepts a “dispatch” parameter. Then, implement it to read the value from local storage using the TOKEN_KEY constant. If a value comes back, have it dispatch the setToken action.
In the App component, import the loadToken thunk. Use it in the mapDispatchToProps by mapping the dispatch of the loadToken thunk to a property of the same name.
Invoke that loadToken method in the componentDidMount method of the App component.
The moment you do that, the page should refresh and you should see the Pokemon browser rather than the login form.
You’re halfway home!