In actual projects, it is necessary to weigh whether to use Redux directly or react redux.
React Redux divides all components into two categories: UI component and container component
UI components
-
It is only responsible for UI rendering without any business logic
-
No state (i.e. this.state variable is not used)
-
All data is provided by the parameter (this.props)
-
Do not use any Redux API s
Container assembly
- Responsible for managing data and business logic, not UI presentation
- With internal status
- Using Redux's API, the UI component is responsible for UI rendering, and the container component is responsible for managing data and logic.
What if a component has both UI and business logic? The answer is to split it into the following structure: there is a container component outside and a UI component inside. The former is responsible for communicating with the outside, transmitting the data to the latter, and the latter renders the view.
React Redux stipulates that all UI components are provided by users, and container components are automatically generated by react redux. In other words, the user is responsible for the visual layer, and the state management is all handed over to it.
connect()
import { connect } from 'react-redux' export default connect( mapStateToProps, mapDispatchToProps )(Count)
The connect method accepts two parameters: mapStateToProps and mapDispatchToProps. They define the business logic of UI components. The former is responsible for input logic, that is, mapping state to UI component parameters (props), while the latter is responsible for output logic, that is, mapping user actions on UI components to actions.
containers/Count.jsx
import React, { Component } from 'react' //Introduce action import { createIncrementAction } from '../../redux/count_action' //Connect is introduced to connect UI components with redux import {connect} from 'react-redux' //Define UI components class Count extends Component { //addition increment = ()=>{ const {value} = this.selectNumber this.props.increment (value*1) } return ( <div> <h1>The current summation is:{this.props.count}</h1> <button onClick={this.increment}>+</button> </div> ) } //Use connect()() to create and expose a container component of Count export default connect( //(state) = > {return count: state} simplified state => ({count:state}), //General writing of mapDispatchToProps /* dispatch => ({ increment:number => dispatch(createIncrementAction(number)), */ //Short for mapDispatchToProps (internal automatic call to dispatch) { increment :createIncrementAction // export const createDecrementAction = data => ({type:DECREMENT,data}) } )(Count)
mapStateToProps() is a function, the first parameter of the connect function. It takes state as the parameter and returns an object. This object has a count attribute, which represents the parameter with the same name of the UI component.
mapDispatchToProps is the second parameter of the connect function, which is used to map the parameters of the UI component to the store.dispatch method. It defines which user actions should be passed to the Store as actions. It can be a function or an object.
If it is a function, you will get two parameters: dispatch and ownProps (props object of container component).
< provider > component
You don't need to pass the store to the container component, just give the package one
index.js
import { Provider } from 'react-redux' import { createStore } from 'redux' import todoApp from './reducers' import App from './components/App' let store = createStore(todoApp); render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
./components/App
export default class App extends Component { render() { return ( {/* <div> <Count store={store}/> <XXX store={store}/> <XXX store={store}/> <XXX store={store}/> </div> ==============Change to*/} <div> <Count/> </div> ) } }
Realize multi-component data sharing
1. Add Person component
containers
— Person,jsx
— Count,jsx
2. The person reducers and Count reducers should be merged by using combineReducers, and the total state after merging is one object
redux/store.js
//createStore is introduced to create the most core store object in redux import {createStore,applyMiddleware,combineReducers} from 'redux' //Introduce reducer serving Count component import countReducer from './reducers/count' //Introduce reducer serving Count component import personReducer from './reducers/person' //Redux thunk is introduced to support asynchronous action s import thunk from 'redux-thunk' //Summarize all reducers to become a total reducer const allReducer = combineReducers({ count:countReducer, persons:personReducer }) //Expose store export default createStore(allReducer,applyMiddleware(thunk))
If there are too many components, you can create a separate folder to summarize all render s
reducers
— person.jsx
— count.jsx
— index.jsx
reducers/index.jsx
/* This file is used to summarize all reducers into a total reducer */ //combineReducers is introduced to summarize multiple reducers import {combineReducers} from 'redux' //Introduce reducer serving Count component import count from './count' //Introduce a reducer that serves the Person component import persons from './person' //Summarize all reducers to become a total reducer export default combineReducers({ count, persons })
/store.js
//reducer after introducing summary import reducer from './reducers' //Redux thunk is introduced to support asynchronous action s import thunk from 'redux-thunk' //Introducing Redux devtools extension import {composeWithDevTools} from 'redux-devtools-extension' //Expose store export default createStore(reducer,composeWithDevTools(applyMiddleware(thunk)))
Note: the store is handed over to the general reducer. Finally, when taking out the status in the component, remember to "take it in place".
export default connect( state => ({ count:state.count, personNum:state.persons.length }), {} )(Count)