1.1 Redux introduces
Article source: Pull hook big front salary boot camp
JavaScript state containers that provide predictable state management
1.2 Redux core concepts and processes
Store: A container for storing state, JavaScript objects
View: An HTML page
Actions: object describing what Actions are taken on state
Reducers: Function that manipulates the state and returns a new state
<! DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, Initial-scale =1.0"> <title>Redux</title> </head> <body> <button id="minus">-</button> <span id="count">0</span> <button id="plus">+</button> <script src="./redux.min.js"></script> <script> // 3. Store default state const initialState = {count: 0} // 2. Function Reducer (state = initialState, action) {switch (action.type) {case 'increment': return {count: state.count + 1 }; case 'decrement': return { count: state.count - 1 }; default: return state; Const store = redux.createstore (reducer); Action Const increment = {type: 'increment'} const decrement = {type: 'decrement'} // 5. Document.getelementbyid ('minus').addeventListener ('click', function () {// 6. Rement action Store.dispatch (Decrement)}) document.getelementByID ('plus').addeventListener ('click', function () { // 6. Get dispatch Trigger Action store.dispatch(increment)}) // Get Store {dispatch: ƒ, subscribe: ƒ, getState: ƒ, replaceReducer: ƒ, Symbol(Observable): ƒ} console.log(store) Store.subscribe (() => {console.log(store.getState()) document.getelementById ('count').innerhtml = store.getState().count }); </script> </body> </html>Copy the code
// Create a store object
const store = Redux.createStore(reducer);
// Get the dispatch trigger action
store.dispatch(increment)
Create the reducer function
function reducer(state = initialState, action) {
switch (action.type) {
case 'increment':
return { count: state.count + 1 };
case 'decrement':
return { count: state.count - 1 };
default:
returnstate; }}Copy the code
// Get the state stored in store
store.getState()
// Changes to subscription data
store.subscribe(() = > {
console.log(store.getState())
});
Copy the code
2. React + Redux
2.1 Problems When Redux is Not used in React
In React, the data flow between components is one-way. The top component can pass data to the lower component through the Props property, but the lower component cannot pass data to the upper component. To enable the lower-level component to modify data, the upper-level component needs to pass the method of modifying data to the lower-level component. As projects get larger, it becomes more difficult to transfer data between components
2.2 Benefits of adding Redux to the React project
Using Redux to manage data, since Store is independent of components, makes data management independent of components and solves the problem of passing data from component to component
npm install redux react-redux
2.3 Redux workflow
The component triggers an Action through the Dispatch method
The Store accepts the actions and distributes them to the Reducer
Reducer changes the state based on the Action type and returns the changed state to the Store
The component subscribes to state in the Store, and state updates in the Store are synchronized to the component
2.4 Procedure for Using Redux
Create the store
// src/store/index.js
import { createStore } from 'redux'
import reducer from './reducers/counter.reducer'
export const store = createStore(reducer)
Copy the code
Use store in the root component
import React from 'react';
import ReactDOM from 'react-dom';
import Counter from './components/Counter'
import { Provider } from 'react-redux'
import {store} from './store'
/** * react-redux * Provider * connect */
ReactDOM.render(
// With the Provider component, store is placed where global components can reach it
<Provider store={store}>
<Counter />
</Provider>.document.getElementById('root'));Copy the code
Create the reducer
// src/store/reducers/counter.reducer.js
import { DECREMENT, INCREMENT } from ".. /count/counter.const";
const initialState = {
count: 0
}
export default function reducer (state = initialState, action) {
switch (action.type) {
case INCREMENT:
return { count: state.count + 1 };
case DECREMENT:
return { count: state.count - 1 };
default:
returnstate; }}Copy the code
// src/store/count/counter.const.js
export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'
Copy the code
Use connect in the component to accept state and dispatch from the store
The connect method takes two arguments and returns a higher-order component.
The first argument to the connect method is the mapStateToProps method, which passes the state of the store to the props of the component. The mapStateToProps method, which takes the state argument, returns an object, which is passed to the component as follows:
const mapStateToProps = (state) = > ({
count: state.count,
a: 'a'.// How to define that a component can or can get a property
})
Copy the code
The second argument to the connect method is the mapDispatchToProps method, which passes the dispatch from the store to the props of the component. The return value of the mapDispatchToProps method is an object, Methods in the object can use Dispatch, and the methods in the object are passed to the component as follows:
const mapDispatchToProps = (dispatch) = > ({
increment () {
dispatch({ type: 'increment'})
},
decrement () {
dispatch({ type: 'decrement'})}})Copy the code
Alternatively, we can create the action function with bindActionCreators in Redux:
import {bindActionCreators} from 'redux'
// bindActionCreators will return an object
const mapDispatchToProps = dispatch= > (
/ / deconstruction. bindActionCreators({ increment () {return { type: 'increment'}
},
decrement () {
return { type: 'decrement'}
}
}, dispatch)
)
Copy the code
Or written
const mapDispatchToProps = dispatch= > bindActionCreators({
increment () {
return { type: 'increment'}
},
decrement () {
return { type: 'decrement'}
}
}, dispatch)
Copy the code
You can also extract the first parameter of bindActionCreators:
import * as counterActions from '.. /store/actions/counter.actions'
const mapDispatchToProps = dispatch= > bindActionCreators(conterActions, dispatch)
Copy the code
// src/store/actions/counter.actions.js
import { DECREMENT, INCREMENT } from ".. /count/counter.const"
export const increment = () = > ({type: INCREMENT})
export const decrement = () = > ({type: DECREMENT})
Copy the code
The connect method accepts mapStateToProps and mapDispatchToProps, returns a higher-order component, and passes in the Counter component for export:
export default connect(mapStateToProps, mapDispatchToProps)(Counter)
The final component code is as follows
// src/components/Counter.js
import React from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import * as counterActions from '.. /store/actions/counter.actions'
function Counter ({count, increment, decrement}) {
return (
<div>
<button onClick={decrement}>-</button>
<span>{count}</span>
<button onClick={increment}>+</button>
</div>)}// 1. Connect will help us subscribe to the store and re-render the component when the state in the Store changes
// 2. The connect method lets us get the state in the store and map the state to the component through the props property of the component
// 3. The connect method lets us get the Dispatch method
const mapStateToProps = (state) = > ({
count: state.count,
a: 'a'.// How to define that a component can or can get a property
})
const mapDispatchToProps = dispatch= > bindActionCreators(counterActions, dispatch)
export default connect(mapStateToProps, mapDispatchToProps)(Counter)
Copy the code
Pass parameters for action
Passing parameters
<button onClick={() => increment(5)}> + 5</button>
Accept the parameters and pass reducer
export const increment = payload= > ({type: INCREMENT, payload})
export const decrement = payload= > ({type: DECREMENT, payload})
Copy the code
Reducer process the data received
export default function reducer (state = initialState, action) {
switch (action.type) {
case INCREMENT:
return { count: state.count + action.payload };
case DECREMENT:
return { count: state.count - action.payload };
default:
returnstate; }}Copy the code
Split reducer
The more states in the store, the more switch branches in the Reducer will be, which is not beneficial to maintenance. Therefore, we need to split the Reducer and merge each small reducer using the combineReducers provided by the Reducer
// src/store/reducers/root.reducer.js
import {combineReducers} from 'redux'
import CounterReducer from './counter.reducer'
import ModalReducer from './modal.reducer'
// { counter: { count: 0 }, modal: { show: false } }
export default combineReducers({
counter: CounterReducer,
modal: ModalReducer
})
Copy the code
const mapStateToProps = (state) = > ({
count: state.counter.count,
})
Copy the code
const mapStateToProps = state= > ({
showStatus: state.modal.show
})
Copy the code
// src/store/index.js
import { createStore, applyMiddleware } from 'redux'
import logger from './middlewares/logger'
createStore(reducer, applyMiddleware(
logger
))
const logger = store= > next= > action= > {
console.log(store)
console.log(action)
next(action) // Don't forget to call next(action)
}
export default logger
// If more than one middleware is registered, the order of execution of the middleware is the order of registration, for example:
createStore(reducer, applyMiddleware(
logger,
test
))
// The order of execution is logger middleware first, then test middleware.
// If the end in the middleware does not call next(action), the entire process is stuck at this point and cannot be executed further
Copy the code