Title: redux tutorial
Foreword: I will encounter redux in the process of learning react. When I learn redux, I often feel that I remember it, but when I use it, I always don't know how to write it, or I always make mistakes when I can use it, so I plan to write a tutorial on redux and record my experience in the process of learning and using it.
1: Meet redux
Official website: redux Chinese network
My understanding: redux is an independent (that is, it does not belong to react and can be used in other frameworks), open source, third-party centralized state manager. Provide predictable status management.
2: Why
So why do we use redux?
We have to mention one of the most common behaviors in react, the communication between components. Let's review the communication between components by the way.
Parent - > child props are passed directly through props
Child - > parent props the parent component passes the function prop, and the child component calls this function and then passes parameters.
Yes - > SUN props or context context provides us with Provider and Consumer
Sun - > props or context also pass parameters in the form of functions
Brother - > brother
State promotion means that the state can be promoted to their common parent component for maintenance, that is, the disguised parent - > child - > parent
Or use the eventBus pattern to create a public container, and then use the publish subscribe pattern to transfer information.
We can clearly know the above way, if it is a simple relationship
For example, it's OK between father and son, but once the relationship becomes complex, we have to take some additional operations to manage the state. If a state needs to be shared by all components, it requires a lot of cumbersome and repetitive work. Therefore, we urgently need a lightweight thing that can share the state to help us solve this problem, redux came into being for such a problem.
3, How to use
Prepare environment
creat-react-app redux-demo
Delete the unnecessary code and create the following directory
|--src | |--class-com | |--|--home.jsx | |--|--about.jsx | |--fun-com | |--|--home.jsx | |--|--about.jsx | |--store |--App.js |--index.js
In the sotre directory, first create an index JS is used to encapsulate the ease of centralized management
The idea of redux is that all UI components have the possibility of triggering status updates, so each UI component can update the status in one way. In order to make the way of updating the status easier to maintain and clear, we specify that the action of triggering updates is called dispatch. How can we distinguish when distributing? In the original distribution, it needs to have two fixed concepts, one is the type of distribution, and the other is the content of distribution. We call this distribution object, which can be expressed in code as follows:
dispatch({ type:'Type of distribution', state:'Content distributed' })
Each of our UI components can be distributed in a similar way to change the state, so the UI component only plays the role of distribution.
Next, the distributed content will be handed over to our store, which will hand over the distributed distribution object to the reducer for execution. In fact, it is the reducer that really works.
The reducer accepts two parameters, one is the last state, and the other is the distribution object. According to different distribution object types, you can return different values to really change the state maintained by the store.
So the reducer code can look like this:
const defaultState = { count: 0 } function reducer (state = defaultState, action) { switch (action.type) { case 'add': return { ...state, count: state.count + action.count } case 'mins': return { ...state, count: state.count - action.count } default: return state } }
Let's go back to the store. Store is a centralized container. We use redux to create it.
import { createStore, applyMiddleware } from 'redux' import reducer from './reducer' const store = createStore(reducer) export default store
4, Complete code
Let's present the complete code and see the effect. Let's improve the class components first.
npm install react-redux
npm install redux-thunk
Install the above two dependencies
//App.js import React, { Component } from 'react' import './App.css' import { connect } from 'react-redux' import About from './class-com/about' import Home from './class-com/home' class App extends Component { render() { const { count } = this.props return ( <div className="App"> <span>store: {count}</span> <h1>Home</h1> <Home/> <h1>About</h1> <About/> </div> ) } } const mapStateToProps = (state)=>({count:state.count}) export default connect(mapStateToProps)(App)
// index.js import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.jsx'; import { Provider } from 'react-redux' import store from './store' ReactDOM.render( <Provider store={store}> <App /> </Provider> , document.getElementById('root'));
//home.js import React, { PureComponent } from 'react' import { connect } from 'react-redux' import { genAdd , genMins , genAsync } from '../store/action' class about extends PureComponent { state = {count:0 , store:0} change = (e)=>{ this.setState({count:Number(e.target.value)}) } render() { const { add , mins , async , count:state } = this.props // console.log(add ,mins , async , state); const { count } = this.state return ( <div> store:{ state } <div> <input type="text" value={count} onChange={this.change}/> <div> <button onClick={()=>add(count)}>plus</button> <button onClick={()=>mins(count)}>reduce</button> <button onClick={()=>async(count)}>Asynchronous addition</button></div> </div> </div> ) } } const mapStateToProps = (state)=>{ return { count:state.count } } const mapDispatchToProps = (dispatch)=>{ return { add:(count)=>{ return dispatch(genAdd(count)) }, mins:(count)=>{ return dispatch(genMins(count)) }, async:(count)=>{ return dispatch(genAsync(count)) } } } export default connect(mapStateToProps, mapDispatchToProps)(about)
about.js and home JS is as like as two peas.
The logic of the above components is written.
Next, create such a directory
store |--const.js |--index.js |--action.js |--reducer.js
//index.js import { createStore, applyMiddleware } from 'redux' import thunk from 'redux-thunk' import reducer from './reducer' const enhancer = applyMiddleware(thunk) const store = createStore(reducer, enhancer) export default store
//const.js export const ADD = 'app/ADD' export const MINS = 'app/MINS' export const ASYNCADD = 'app/ASYNCADD'
//reducer.js import { ADD, MINS } from './const' const defaultState = { count: 0 } function reducer (state = defaultState, action) { switch (action.type) { case ADD: return { ...state, count: state.count + action.count } case MINS: return { ...state, count: state.count - action.count } default: return state } } export default reducer
// action.js import { ADD, MINS } from './const' const getNum = (num) => { return new Promise((resolve) => { setTimeout(() => { resolve(num); }, 1000) }) } export const genAdd = (payload) => ({ type: ADD, count: payload }) export const genMins = (payload) => ({ type: MINS, count: payload }) export const genAsync = (payload) => { return async (dispatch) => { const num = await getNum(payload) return dispatch(genAdd(num)) } }
The above is the whole Demo built. If there is no accident, it will be like the following effect.
The state in the store is shared globally and can be changed in any component.
Conclusion: in fact, react redux has a series of functional hooks that can be used. We'll share how to use functional redux next time.