preface
Recently, I learned react-Native and got stuck in React-Redux. It took some time and effort to understand its principle and data flow. I drew a picture to explain it. The person that hopes to see this article had better have some understanding to Redux, if do not understand, can go looking next ruan yifeng’s article. Some explanations are personal understanding, not very rigorous, if there is a wrong place, please correct.
Data flow diagram
Here is the code from Nguyen yifeng’s blog, with some modifications for React-Native.
Root.js // Create a store global management state and operation const store = createStore(reducer); // Provider extends a layer around the root component <App>, so all child components of the App can be passed to the store by default, via the component propsexport default class Root extends Component {
render() {
return (
<Provider store={store}>
<App/>
</Provider>
)
}
}
Copy the code
App.js // view extends Component {render() {// The state of the View is derived from the props, while the store const {value, onIncreaseClick} = this.propsreturn(<div> <span>{value}</span> <button onClick={onIncreaseClick}>Increase</button> </div>)}} // connect the UI component and container component together const App = connect( state =>({ value: State.count // input, set the state in store to props}), dispatch =>({// output, bind the action as props to the View, and distribute the user action type onIncreaseClick: () => dispatch(increaseAction.increase()) }) )(Counter)export default App
Copy the code
Increaseaction.js // Define the type of actionexport const INCREMENT = 'INCREMENT'; The action creation function simply returns an actionexport function increase(params) {
return {
type: INCREMENT, data:data}; }Copy the code
CounterReducer. Js // Provide an initial state initState={count: 0} // By determining the Action type, return the state object after the new data change, even if there is no state change, return an objectexport default function counter(state = initState, action) {
const count = state.count
switch (action.type) {
case INCREMENT:
return { count: count + 1 }
default:
return state
}
}
Copy the code
React-redux: React-Redux: React-Redux: React-Redux: React-Redux: React-Redux: React-Redux
1. In this example, the View component only provides the UI, without its own states and operations. What causes the interface change?
Is the props of the View itself. We know that the initial state of the component is determined by the props. Although there is no state of its own, if its props changes, the interface will also change.
2. What is the content of props of a View provided? How to differentiate props of multiple views?
Provided by the state in the globally unique store of the application, all states are stored in an object, distinguished by keys.
3. Where does store come from?
Create the state object by store = createStore(reducer). The reducer returns exactly the changed state object.
Reducer — (Store /state) — provider — (state/props) — view
Reducer (state,action) — Reducer (state,action) — reducer(state,action)
This function is internally processed by store.dispatch(action). First look at createStore(Reducer).
function createStore = ( reducer ) => {
letcurrentState; // Internal stateletlisteners = []; // All listeners const getState = () => currentState; // Obtain state // dispatch from the store by internally implementing the reducer() function, where action and reducer intersect, Const dispatch = (action) => {currentState = reducer(state, action); // Update state listeners. ForEach (listener => listener()); Const subscribe = (listener) => {listeners. Push (listener);return()=>{ listeners = listeners.filter(l => l ! == listener) } }return {
getState,
dispatch,
subscribe
}
}
Copy the code
This is all due to connect and Provider in react-Redux. If they are not used, the code in app.js above should be as follows:
class Counter extends Component{
componentWillMount(){store. Subscribe ((state)=>this.setState(state))}render() {
return<div> <span>{value}</span> // click post dispatch event type <button onClick={()=>store.dispatch(increaseAction.increase())}>Increase</button> </div> ) } }Copy the code
5. After the reducer() function was executed, how was the state changed?
See the createStore code in Question 4. The simplified version can be written as:
function createStore = ( reducer ) => {
letcurrentState; // Internal state const getState = () => currentState; State const dispatch = (action) => {currentState = reducer(state, action); }return {
getState,
dispatch,
}
}
Copy the code
The above two problems have solved and explained the data flow in the right part of the figure, view — (action) — dispatch — (action) — Reducer. When the two data cycles are combined, they form a circle and complete the great harmony of life. The diagram below:
Multiple Reducer
After looking at the above analysis, we expand again. In the figure above, there is only one Reducer. There are many views in the normal APP, so there are naturally many corresponding reducer.
If a loginreducer.js file had been added to the above project, it would look like this:
LoginReducer. Js // Provide an initial state initState={login:false} // By determining the type of the Action, return the state object after the new data change, even if no state change, return an objectexport default function login(state = initState, action) {
const login = state.login
switch (action.type) {
case INCREMENT:
return{ login: ! login } default:return state
}
}
Copy the code
This Reducer performs one operation, receives the operation type INCREMENT and reverses the login state once. If I click that button again, does the login status change as count increases? The answer is yes! So why is that?
Yes if you use the following code:
const rootReducer = combineReducers({
counter: counter,
login:login
});
store=createStore(rootReducer);
Copy the code
CombineReducers, as its name implies, merges the Reducer function object into a single reducer function, which traverses all the sub-reducer members and integrates the results into a single state tree, so there is only one reducer at last. Repeat, Finally there is only one reducer function! The rough code for combineReducers is as follows:
export default functionCombineReducers (reducers) {var reducerKeys = object. keys(reducers) var finalReducers = {} // Extract the value in the reducers asfunctionPart of thefor (var i = 0; i < reducerKeys.length; i++) {
var key = reducerKeys[i]
if (typeof reducers[key] === 'function') {
finalReducers[key] = reducers[key]
}
}
var finalReducerKeys = Object.keys(finalReducers)
return function combination(state = {}, action={}) {
var hasChanged = falseVar nextState = {} /** * iterate through access to finalReducers */for(var i = 0; i < finalReducerKeys.length; I ++) {var key = finalReducerKeys[I] var reducer = finalReducers[key] /** * Reduce state by reducer name * Each key corresponds to state */ var previousStateForKey = state[key]; var nextStateForKey = reducer(previousStateForKey, action) nextState[key] = nextStateForKey hasChanged = hasChanged || nextStateForKey ! == previousStateForKey }return hasChanged ? nextState : state
}
}
Copy the code
As can be seen from the above code, when an action is dispatched, all reducer functions are executed once and the corresponding state is modified through action.type, so that all views subscribed to the corresponding state will be changed. So the answer to the above question is yes. Finally, put another chart, which is the data flow chart when there are multiple Reducer and actions.
store
state
reducer
action
conclusion
To sum up, the View is responsible for the UI interface. Redux manages the state and operations in the View in the Store, and then passes the modified state content to the View through props. The interface changes. In the user operation interface, View performs related operations through Dispatch, and sends ActionType and Data to the Reducer function to modify state according to ActionType and Data.
Thank you
- React-redux connect method
- Redux In Chinese
- The React – the use of the story
The last
Please like and follow.
Welcome to my GitHub homepage. If you like, please follow me.