Practical experience of react: detailed explanation of connect method of react Redux

Time:2021-1-18

Reprinted note:

  • The author is Ye Zhai of Taobao front-end team. I like this article very much, so I rearrange it and reprint it here. At the same time, I also add some of my own experience.
  • Original address:http://taobaofed.org/blog/201…

Redux is one of the most important components of react. It tries to provide a predictable state management mechanism for react applications. Redux itself is simple enough to support other interface frameworks besides react. So if you want to use Redux and react together, you need some additional tools, the most important of which is react redux.

React Redux provides two important objects,ProviderandconnectThe former makesReactThe component can be connected, which connects the react component with the store of redux. In the document of react Redux, theconnectWhen I first learned Redux, I read this document for a long time, but I didn’t understand all the meanings of it.

After using Redux for a period of time, this article tries to come back here again and give you some adviceThis is the documentA reliable interpretation.

Preparatory knowledge

First, let’s review the basic usage of redux. If you haven’t read the Redux document, you must go firstreadonce.

const reducer = (state = {count: 0}, action) => {
  switch (action.type){
    case 'INCREASE': return {count: state.count + 1};
    case 'DECREASE': return {count: state.count - 1};
    default: return state;
  }
}

const actions = {
  increase: () => ({type: 'INCREASE'}),
  decrease: () => ({type: 'DECREASE'})
}

const store = createStore(reducer);

store.subscribe(() =>
  console.log(store.getState())
);

store.dispatch(actions.increase()) // {count: 1}
store.dispatch(actions.increase()) // {count: 2}
store.dispatch(actions.increase()) // {count: 3}

adoptreducerCreate astoreEvery time westoreupperdispatchOneactionstoreThe data in will change accordingly.

Of course, we can use Redux directly in react: initialize in the outermost container componentstore, and thenstateProperties on aspropsPass it on layer by layer.

class App extends Component{

  componentWillMount(){
    store.subscribe((state)=>this.setState(state))
  }

  render(){
    return (
      <Comp
        state={this.state}
        onIncrease={()=>store.dispatch(actions.increase())}
        onDecrease={()=>store.dispatch(actions.decrease())}
      />
    )
  }
}

Reprinted note:

  • Another way is in the entry fileindex.jsInitialization instore, andexportCome out, thenimportGo to the file that defines the component.

But that’s not the best way. The best way is to use react reduxProviderandconnectmethod.

Using react Redux

First, in the outermost container, wrap everything in a containerProviderComponent, thestoreAspropPass on toProvider

const App = () => {
  return (
    <Provider store={store}>
      <Comp/>
    </Provider>
  )
};

ProviderAny of the components in theComp), if necessarystateThe data in must be the “connected” componentconnectMethod for the “component you write”(MyComp)After packaging.

class MyComp extends Component {
  // content...
}

const Comp = connect(...args)(MyComp);

soconnectMethod is the top priority.

connect

Exactly?connectWhat does the method do? Let’s explore it.

First, let’s look at the signature of the function

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

connect()Receive four parameters, which aremapStateToPropsmapDispatchToPropsmergePropsandoptions

mapStateToProps

mapStateToProps(state, ownProps) : stateProps

This function allows us tostoreData in aspropsBind to a component.

const mapStateToProps = (state) => {
  return {
    count: state.count
  }
}

The first parameter of this function is reduxstoreAnd we’ve got something out of itcountProperty. Because returned withcountProperty, soMyCompWill be known ascountOfpropsField.

class MyComp extends Component {
  render(){
    Return < div > count:{ this.props.count }Times < / div >
  }
}

const Comp = connect(...args)(MyComp);

Of course, you don’t have tostateThe data in is passed into the component intact, which can be changed according to thestateTo dynamically output the (minimum) attributes required by the component.

const mapStateToProps = (state) => {
  return {
    greaterThanFive: state.count > 5
  }
}

The second argument to the functionownPropsYesMyCompownprops. sometimes,ownPropsIt will also have an impact on it. For example, when you arestoreA list of users is maintained in, and your componentsMyCompOnly care about one user (viapropsInuserId(embodiment).

const mapStateToProps = (state, ownProps) => {
  //State is {userlist: [{ID: 0, name: 'Wang Er'}]}
  return {
    user: _.find(state.userList, {id: ownProps.userId})
  }
}

class MyComp extends Component {
  
  static PropTypes = {
    userId: PropTypes.string.isRequired,
    user: PropTypes.object
  };
  
  render(){
    Return < div > User Name:{ this.props.user .name}</div>
  }
}

const Comp = connect(mapStateToProps)(MyComp);

WhenstateChange, orownPropsWhen things change,mapStateToPropsWill be called to calculate a newstatePropsIn relation toownPropsAfter merge) update toMyComp

That’s how ReduxstoreThe basic way to connect data in to components.

Reprinted note:

  • What is it called“MyCompownprops”?Suppose you don’t use react redux,MyCompThe parent component of isParentCompSo the aboveownPropsyesParentCompPass on toMyCompFor the methods belowmapDispatchToPropsThe same is true.in other words,ownPropsWith ReduxstoreAndstateNothing at all
  • methodmapStateToPropsbyMyCompThe added property cannot be used by the methodmapDispatchToPropsAccess to, and vice versa.Because, this involves the timing and order of render, the author has stepped on a lot of holes in it. As for why I have this demand, because I designed a button, the function is: after clicking, calculate the next state according to the current state, and update. I’ve been through a loterrorAfter that, I finally realized that react Redux is not designed to solve this kind of problem at all. There are two solutions: one is to update the reducer directly according to the state when designing it; the other is to import the global datastoreAnd usestore.getState()Get currentstateAnd then according to thisstateUpdate.
  • In addition, if you usePropTypesyesMyCompDo attribute type check, methodmapStateToPropsAnd methodsmapDispatchToPropsbyMyCompThe added property exists.

mapDispatchToProps

mapDispatchToProps(dispatch, ownProps): dispatchProps

The second parameter of connect ismapDispatchToPropsIts function is toactionAspropsBind toMyCompIt’s on.

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    increase: (...args) => dispatch(actions.increase(...args)),
    decrease: (...args) => dispatch(actions.decrease(...args))
  }
}

class MyComp extends Component {
  render(){
    const {count, increase, decrease} = this.props;
    return (<div>
      < div > count:{ this.props.count }Times < / div >
      < button onclick = {increase} > increase < / button >
      < button onclick = {decrease} > reduce < / button >
    </div>)
  }
}

const Comp = connect(mapStateToProps, mapDispatchToProps)(MyComp);

becausemapDispatchToPropsMethod returns aincreaseAttributes anddecreaseProperty, these two properties also becomeMyCompOfprops

As shown above, callactions.increase()Only oneactionobject{type:'INCREASE'}To trigger thisactionMust be instoreCall updispatchmethod.dispatchExactlymapDispatchToPropsThe first parameter of. However, in order not to be perceived by the mycomp componentdispatchFor the existence of the world, we need toincreaseanddecreaseTwo functions are packaged to make them directly callable (that is, calling the method triggers adispatch)。

Redux itself providesbindActionCreatorsFunction to set theactionPackaged as a function that can be called directly.

import {bindActionCreators} from 'redux';

const mapDispatchToProps = (dispatch, ownProps) => {
  return bindActionCreators({
    increase: action.increase,
    decrease: action.decrease
  });
}

Again, whenownPropsWhen it changes, the function will also be called to generate a new onedispatchPropsIn relation tostatePropsandownPropsAfter merge) update toMyComp. be careful,actionThe change of will not cause the above process, defaultactionIt is fixed in the life cycle of a component.

Reprinted note:

  • functionconnecteven to the extent thatreact-reduxThe core of Redux is to bind the state of store in Redux to the properties of components, so that the modification of state can be directly reflected as the change of component appearance. Therefore, the parametermapStateToPropsIt’s very important, but the parametersmapDispatchToPropsIt’s superfluous – because simply and rudely importing the global store can also achieve the same purpose (in fact, this is what I do).

mergeProps

[mergeProps(stateProps, dispatchProps, ownProps): props]

As I said before, no matter whatstatePropsstilldispatchPropsWe all need to talk to each otherownPropsMerge will be assigned toMyCompconnectThe third parameter of is used to do this. Usually, you don’t need to pass this parameter,connectWill useObject.assignInstead of this method.

other

Finally, there’s another oneoptionsThe options are relatively simple, and they are rarely used (especially when you follow some of the “best practices” of react). Hope to understand the students can directly look at the document.

(end)