Search:   Dictionary All Posts
Store Your Knowledge at the Brain Bank!

Redux

By Jamie in Lessons / Programming - React  1.11.19  
Summary - Create a store. Subscribe to the store. Create the root reducer. Provide access for the store to the App. mapStateToProps in a component. mapDispatchToProps in a component. Connect component props to maps. Create actions. Process the actions in the reducer.
index.js  - typical example using thunk middleware for ajax calls and redux-logger to track details. includes reducer with multiple reducers, which is typical, if only one reducer is needed, then combineReducers is unnecessary.

imports

1. import { createStore, applyMiddleware, combineReducers } from 'redux'
2. import { Provider } from 'react-redux'
3. import { createLogger } from 'redux-logger'
4. import thunkMiddleware from 'redux-thunk'
5. import { oneReducer, twoReducer }  from './reducers'

consts
1. const rootReducer = combineReducers( { oneReducer, twoReducer } )
2. const store = createStore ( rootReducer, applyMiddleware(thunkMiddleware, logger)  )

wrapper
1. <Provider store={store}><App /></Provider>

App.js - (or in any container w/state related functions)

1. import { connect } from 'react-redux'


2. mapStateToProps
- this function gets in the state (state is passed into it as its parameter, which comes from the connect function (4 below) which comes from the index.js file <Provider store={store}><App/></Provider> function).
- it returns an object with properties which can be used in the component's props

const mapStateToProps = state => {
    return {
        propertyToProps:  state.nameOfReducer.propertyFromReducer
    }
}

3. mapDispatchToProps

Understand Better what Redux is - its a data store. Its an object. The rootReducer is an object of objects. you pass the root reducer into the createStore(function), then pass the store to the main App - now, the main app and everything contained within it, has access to the redux store.

when you mapStateToProps you going through the entire state and picking just what you need for that one component and passing it in, as an object that is accessible in the component's props'

another great article on how connect()() works, as well as mapStateToProps and maptdispatch to props

4. export default connect(mapStateToProps, mapDispatchToProps)(App)
- in redux there is a property called 'subscribe' but it involves a bit of work to get working properly, so in react-redux there is a higher order function (a function that takes in a function) called 'connect' that handles the 'subscribe' and makes it easy. all you do is wrap your exported component in the connect function, pass in two other functions, mapStateToProps and mapDispatchToProps, and return the component like this .... connect(mapStateToProps, mapDispatchToProps)(App)

Middleware
Middleware is just a tunnel that reducers go through before getting to the store. 

Once a reducer function is called, thunk reads the function and determines of the reducer is returning an object, if it does it ignores it, however, if it sees a function, like a dispatch(), it will act upon it. 

Reducers
Reducers are pure functions that take in an old state and return a new state to the redux store. They are pure in that they do not mutate any data and they always return a value.

Reducer functions in redux define the state and return it to the store. It will likely take in a state set to a default value of the initial state. If no action is called, such as the first time the app runs, the initial state will be added to the redux store.

If an action is dispatched to a reducer, the reducer will make a copy of the old state (it will not change/mutate the old state), and it will change whatever is called for by the action and the new state will be returned to the redux store.

Any component that relies on data from the store will be populated with appropriate data. If the store is updated with new data, every dependent container in the app will be re-rendered to include the new state.

Actions
An action is a function that returns an object that will be 'dispatched' to the reducer. This object will contain two things, the type of action it is and the payload, which will include the data to be passed along with the action type.

The root reducer will receive the action and it will filter through all of the switch cases in the entire store in search for the action.type that matches the dispatched action.type.

- dispatch()
The dispatch function is passed into mapDispatchToProps by the HOC connect() function within the component in the same way that state is passed into the mapStateToProps. it becomes a property value of the component's props that was created in the mapDispatchToProps function. When that function is called within the component, it runs dispatch() which runs the function contained within it and sends the result to the rootReducer.

- The Root Reducer - Combing all Reducers
There will likely be multiple reducers when you create an app that uses redux. After all, you are trying to track the complex state of the app. If the state isn't that complex, or it can be tracked on just one page, then you probably don't need to use a state store anyway.

In your reducers folder you create a rootReducer.js file. This file will import all reducers. It will also import a function that comes with redux called 'combineReducers'.  You create a new const called rootReducer equal the result of the combineReducers() function. The combineReducers function takes in all of the reducers and combines them into one object. When you pass in the newly formed rootReducer to the createStore() function, the store is thus created and it contains all the states provided by all of the reducers.

Here is the root reducer page...

import reducer1 from './reducer1'
import reducer2 from './reducer2'
import reducer3 from './reducer3'
import { combineReducers } from 'redux'

const rootReducer = combineReducers ({
    reducer1: reducer1,
    reducer2: reducer2,
    reducer3: reducer3
})

export default rootReducer

Then, on your home app page, either app.js or index.js, or whichever you chose to run your createStore function, you only import your rootReducer and only pass it along to the store, like this...

import { createStore } from 'redux'
import rootReducer form './store/reducers/rootReducer'

const store = createStore(rootReducer)


Actions in Summary
- You have an action, which is a function that returns an object.
- On the component page, you have a mapDispatchToProps function, which returns an object with a property equal to a function that returns the dispatch function, which takes in the action function that was imported in the component, which takes in a parameter. In the component, when the props function is called, it passes in any kind of data and the dispatch function runs, which runs the action with the parameter passed in from the component props call, and it also alerts the rootReducer to pay attention to the results of the action function.
- The action function returns an object with a 'type' property and a 'payload' property.

Thunk Middleware
thunk is a redux middleware that will look for functions returned from an action with the purpose of allowing async actions to run within the dispatched action. async can't otherwise run in redux actions, they can only return objects.

here is how it works...
if a function is returned instead of an object, then thunk will stop the dispatch and handle the function from here. thunk will use its own dispatch and getState functions which will be passed in as the two parameters of the function. With the redux dispatch stopped, you can do other stuff, like make database queries, or fetch api calls, ultimately it will run its own dispatch function, which is the same as the redux dispatch function, which simply returns an object, which ultimately gets passed to the reducer.