You can’t doubt yourself because of others, but you can inspire yourself through others!
Yesterday someone let I regard him as a small white about redux, I sort out said logic is not very clear, he may be in teaching me how to write an article, I wrote to myself, is not responsible for, to strengthen their short time memory always stay in, I will arrange time to do the article before logical combing, first, of course, from the beginning.
We know that react component transfer is one-way, if the component relationship is too far away or there is no relationship, we will be in trouble, redux is to solve this problem, it stores data to the warehouse, and distributes action actions via Reducer to substrict
There are five redux
- CreateStore Creates the repository and accepts reducer as the parameter
- BindActionCreator binds the relationship between store.dispatch and action
- CombineReducers Merges multiple reducers
- ApplyMiddleware The middleware of the onion model, between dispatch and action, rewrites dispatch
- Compose integrates multiple middleware
createStore
Main export getState, dispatch, subscribe three methods, respectively is access to the warehouse, distributing action and subscribe to the event. Generate the store, which contains all data, and get the data by getState, one State for each View. As long as the State is the same, the View is the same.
The internal store of a state tree, the state tree is any type, when the state tree will copy the state tree, and export, to prevent malicious changes to the state tree.
Therefore, you can only change the state by sending dispatch, which calls Reducer to handle the action action. Reducer is a function that takes state and action. Action is an object with a type attribute to indicate which state it has changed
At the same time, when the state changes will trigger the subscribe listening event
export default function createStore(reducer,initState,enchancer) {
if (enchancer) {
return enchancer(createStore)(reducer,initState);
}
// A state tree is stored inside the repository. It could be any type
let state;
let listeners=[];
function getState() {
return JSON.parse(JSON.stringify(state));
}
// The component can assign actions to the repository
function dispatch(action) {
// Call Reducer to process the old state and calculate the new state
state=reducer(state,action);
// Notify other components
listeners.forEach(l= >l());
}
// If other components need to subscribe to state change times,
function subscribe(listener) {
listeners.push(listener);
return function () {
listeners = listeners.filter(item= >item! ==listener); } } dispatch({type:'@@INIT'});
return {
getState,
dispatch,
subscribe
}
}
Copy the code
bindActionCreator
Dispatch (()=>{type:add}) and dispach ()=>{type:add}). Dispatch (()=>{type:add}) At this point we need to establish the relationship between dispatch and actions
<button onClick={()=>bindActions.add1(1)}>+</button>
export default function (actions,dispatch) {
//actions = {add(){return {type:ADD}},minus(){return {type:'MINUS'}}}
return Object.keys(actions).reduce(
(memo,key) = > {
memo[key]=(. args) = >dispatch(actions[key](... args));returnmemo; }, {}); }Copy the code
combineReducers
Return a function that represents the merged reducer, so it must have two parameters and finally returns the new state. We iterate reducers for each attribute
Redux applications can have only one repository and only one Reducer
// Combine multiple Reducer functions into one
export default function (reducers) {
// The function returned is the reducer after the merge
return function (state={},action) {
let newState={};
for (let key in reducers) {
// key=counter1
/ / reducers [counter1] = counter the reducer
// State Indicates the merged state tree
//if (key===action.name) {
newState[key]=reducers[key](state[key],action);/ / state [key] the old state
/ /}
}
returnnewState; }}Copy the code
We can see that each component needs to get the repository, manage subscriptions, and distribute events to the repository, and that’s very comfortable, and we need to reuse that logic, either with higher-order components, or with functions as subcomponents, so we’re using this library
applyMiddleware
The middleware is probably the hardest part of Redux to understand
We can send action to the repository to change the state by using the Reducer. After the state changes, we can modify the view. The user can click on the view with the mouse, and the view will dispatch action to change the state, forming a cycle. Sometimes we need to publish an asynchronous operation, and we want to do some extra action before dispatch and after dispatch, so we need to plug in the middleware, and the way we do that is we get the dispatch method, override the Dispacth, and we use what we call source code parsing
A redux middleware might look like this, and then I will compare Redux to Express and KOA middleware to summarize
function logger(store){//getState, new dispatch
return function(next){/ / store. Dispatch the old
return function action(){
console.log('old');
next()
console.log('new')}}}// The parse process
let logger = store= > next =>action= >{}// The following is the process
function applyMiddleware(middleware){
return function(creacteStore){
return function(reducer){
let store = creacteStore(reducer);
let middleware2 = middleware(store)
let dispatch = middleware2(store.dispatch)
}
}
}
let store = applyMiddleware(logger)(creacteStore)(reducer)
Copy the code
import compose from './compose';
export default function (. middlewares) {
return function (createStore) {
return function (reducers) {
let store=createStore(reducers);// This is the original warehouse dispatch
let dispatch;// The dispatch method points to the new dispatch method
let middlewares2 = middlewares.map(middleware= >middleware({
getState: store.getState,
dispatch:action= >dispatch(action)
}));// Call the first layer to removedispatch=compose(... middlewares2)(store.dispatch);// Make a second call to remove the second layer
return {
...store,
dispatch
}
}
}
}
Copy the code
Compose Integrated Middleware
function add1(str) {
return 1+str;
}
function add2(str) {
return 2+str;
}
function sum(a,b) {
return a+b;
}
//let ret=add1(add2(add3('zdl')));
//console.log(ret);
function compose1(. fns) {//[add1,add2,add3]
return function (. args) {
let last=fns.pop();
return fns.reduceRight((val,fn) = >fn(val),last(...args));
}
}
export default function(. fns) {
return fns.reduce((a,b) = >(. args) = >a(b(... args))); }/** * let ret =add1 (add2(... Args)) * The second time (... args)=>add1(add2(sum(... args))) */
let ret=compose(add1,add2,sum)('a'.'b');
console.log(ret);//123zdl
Copy the code
react-redux
There are four files
- Connect maps store and Dispatch to props property objects, respectively, and returns components
- Exporting the Provider,, and consumer
- A Provider is a component that accepts a store and passes it to all its children via the Context API. The benefits are similar to routing
- index
index
import Provider from './Provider';
import connect from './connect';
export {
Provider,
connect
}
Copy the code
Provider
/** * is a component that accepts a store and passes it through its hand to all its children through the Context API */
import React,{Component} from 'react'
import {Provider as StoreProvider} from './context';
import PropTypes from 'prop-types';
export default class Provider extends Component{
// Specifies that if someone wants to use this component, they must provide a redux repository property
static propTypes={
store:PropTypes.object.isRequired
}
render() {
let value={store:this.props.store};
return (
<StoreProvider value={value}>
{this.props.children}
</StoreProvider>)}}Copy the code
context
import React from 'react'
let {Provider,Consumer}=React.createContext();
export {Provider,Consumer};
Copy the code
connect
This is a higher-order functions, introduced two methods respectively mapStateToProps, mapDispatchToProps, to store and dispatch map respectively into props attribute object, so the page doesn’t need to drink warehouse, There is no need to bind action and Dispatch, and no need to subscribe to the status of the return component
import {Consumer} from './context';
import React,{Component} from 'react';
import {bindActionCreators} from '.. /redux';
MapStateToProps is a function that maps the state to a property object. MapDispatchToProps is also a function that maps the dispatch method to a property object
export default function (mapStateToProps,mapDispatchToProps) {
return function (Com) {
// Connect the repository to the component in this component
class Proxy extends Component{
state=mapStateToProps(this.props.store.getState())
componentDidMount() {
this.unsubscribe = this.props.store.subscribe((a)= > {
this.setState(mapStateToProps(this.props.store.getState()));
});
}
componentWillUnmount = (a)= > {
this.unsubscribe();
}
render() {
let actions={};
// If mapDispatchToProps is a function, execute it and get the property object
if (typeof mapDispatchToProps === 'function') {
actions = mapDispatchToProps(this.props.store.dispatch);
// If mapDispatchToProps is an object, we need to bind it manually
} else {
actions=bindActionCreators(mapDispatchToProps,this.props.store.dispatch);
}
return<Com {... this.state} {... actions}/> } } return () => ( <Consumer> { value => <Proxy store={value.store}/> } </Consumer> ); }}Copy the code