1.React-Redux基础用法
index.js
// import ReactDOM from 'react-dom'
import React from "react"
import App from "./App"
import { Provider } from "react-redux"
import store from "./store"
// ReactDOM.render(<App />, document.getElementById('root')) // before
import { createRoot } from 'react-dom/client'
const container = document.getElementById('root')
const root = createRoot(container) // createRoot(container!) if you use TypeScript
root.render(
<Provider store={store}>
<App tab="home" />
</Provider>
)
store/index.js
import { createStore } from "redux"
import reducer from "./reducer"
const store = createStore(reducer)
export default store
action.js
import { ADD_COUNT } from "./constants"
export const addAction = (num) => {
console.log('num', num)
return {
type: ADD_COUNT,
num
}
}
constants.js
export const ADD_COUNT = 'ADD_COUNT'
reducer.js
import { ADD_COUNT } from "./constants"
const initialState = {
count: 1
}
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_COUNT:
return { count: state.count + action.num }
default:
return state
}
}
export default reducer
about.js
import React from "react"
import { connect } from "react-redux"
// import connect from "../../store/connect/connect"
import { addAction } from '../../store/action'
class About extends React.PureComponent {
render() {
return (
<div id={'about'}>
About-----------
<div>{this.props.count}</div>
<button onClick={() => this.props.increment()}>++</button>
</div>
)
}
}
const mapStateToProp = (state) => {
return {
count: state.count
}
}
const mapStateToAction = (dispatch) => {
return {
increment() {
dispatch(addAction(1))
}
}
}
export default connect(mapStateToProp, mapStateToAction)(About)
connect的实现原理
import React from "react"
import store from '../index'
function connect(mapStateToProp, mapStateToAction) {
return function enhanceComponent(WrapComponent) {
class AdvComponent extends React.PureComponent {
constructor (props) {
super(props)
console.log('this/props', this.props)
this.state = {
...mapStateToProp(store.getState())
}
}
componentDidMount() {
store.subscribe(() => {
this.setState({
...mapStateToProp(store.getState())
})
})
}
render() {
return (
<WrapComponent {...this.props} {...this.state} {...mapStateToAction(store.dispatch)}></WrapComponent>
)
}
}
return AdvComponent
}
}
export default connect
redux-thunk
/*
使用redux-thunk之前:
--------------------
------> | Component 异步请求 | -----
| -------------------- |
| ↓
------------- ------------- -------------
| Store | <---- | Reducer | <---- | Action |
------------- ------------- -------------
使用redux-thunk之后:
-------------
---------> | Component | ---------------------------------
| ------------- |
| ↓
------------- ------------- ------------- -------------
| Store | <---- | Reducer | <---- | 异步请求 | <---- | Action |
------------- ------------- ------------- -------------
* */
安装
npm install redux-thunk
引用
store/index.js
import { createStore, applyMiddleware } from "redux"
import thunkMiddleware from "redux-thunk"
import reducer from "./reducer"
// 创建store之前,通过applyMiddleware方法,告诉Redux需要引用哪些中间件
const storeEnhancer = applyMiddleware(thunkMiddleware)
// 利用store来保存状态(state)
const store = createStore(reducer, storeEnhancer)
export default store
应用中间件
action.js
import { ADD_COUNT, CHANGE_ACTION } from "./constants"
export const addAction = (num) => {
console.log('num', num)
return {
type: ADD_COUNT,
num
}
}
export const changeAction = (info) => {
return {
type: CHANGE_ACTION,
info
}
}
export const getInfo = (dispatch, getState) => { // 引用中间后提供的两个参数 dispatch, getState
fetch('http://127.0.0.1:7001/info')
.then((res) => {
return res.json()
})
.then((data) => {
dispatch(changeAction(data))
})
.catch(error => {
console.log('error', error)
})
}
constant.js
export const ADD_COUNT = 'ADD_COUNT'
export const CHANGE_ACTION = 'CHANGE_ACTION'
reducer.js
import { ADD_COUNT, CHANGE_ACTION } from "./constants"
const initialState = {
count: 1,
info: {}
}
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_COUNT:
return { ...state, count: state.count + action.num }
case CHANGE_ACTION:
return { ...state, info: action.info }
default:
return state
}
}
export default reducer
...state
: 将所有数据返回
About.js
import React from "react"
import { connect } from "react-redux"
// import connect from "../../store/connect/connect"
import { addAction, getInfo } from '../../store/action'
class About extends React.PureComponent {
componentDidMount() {
this.props.getInfo()
}
render() {
return (
<div id={'about'}>
About-----------
<div>{this.props.count}</div>
<button onClick={() => this.props.increment()}>++</button>
<div>{this.props.info.name}</div>
<div>{this.props.info.age}</div>
</div>
)
}
}
// 在mapStateToProps方法中告诉React-Redux, 需要将store中保存的哪些数据映射到当前组件的props上
const mapStateToProp = (state) => {
return {
count: state.count,
info: state.info
}
}
// 在mapDispatchToProps方法中告诉React-Redux, 需要将哪些派发的任务映射到当前组件的props上
const mapStateToAction = (dispatch) => {
return {
increment() {
dispatch(addAction(1))
},
getInfo() {
// redux-thunk中间件作用:
// 可以让dispatch方法可以接收一个函数, 可以让我们在通过dispatch派发任务的时候去执行我们传入的方法
dispatch(getInfo)
}
}
}
export default connect(mapStateToProp, mapStateToAction)(About)
redux-thunk的实现原理
const redux = require('redux');
// 定义一个状态
let initialState = {
count: 0
};
// 利用store来保存状态(state)
const store = redux.createStore(reducer);
// 利用action来修改状态
const addAction = {type:'ADD_COUNT', num: 1};
const subAction = {type:'SUB_COUNT', num: 1};
const getUserInfo = (dispatch, getState)=>{
setTimeout(()=>{
console.log('获取到了异步数据');
dispatch(addAction);
}, 3000);
};
// 利用reducer将store和action串联起来
function reducer(state = initialState, action) {
console.log('reducer被执行了');
switch (action.type) {
case 'ADD_COUNT':
return {count: state.count + action.num};
case 'SUB_COUNT':
return {count: state.count - action.num};
default:
return state;
}
}
// 在组件中如何修改Store中存储的状态?
/*
console.log('执行reducer之前做的事情');
store.dispatch(addAction);
console.log('执行reducer之前做的事情');
store.dispatch(subAction);
*/
/*
在redux-thunk中, 如果通过dispatch派发的任务是一个对象, 那么就立即执行reducer
如果通过dispatch派发的任务是一个函数, 那么就执行这个函数
* */
/*
function thunkDispatch(action) {
// console.log('执行reducer之前做的事情');
// store.dispatch(action);
if(typeof action === 'function'){
action(store.dispatch, store.getState);
}else{
store.dispatch(action);
}
}
// thunkDispatch(addAction);
thunkDispatch(getUserInfo);
*/
function thunkDispath(store) {
const storeDispath = store.dispatch;
const storeGetState = store.getState;
function myDispatch(action) {
if(typeof action === 'function'){
action(storeDispath, storeGetState);
}else{
storeDispath(action);
}
}
// 将官方的dispatch函数修改为我们自定义的dispatch函数
store.dispatch = myDispatch;
}
thunkDispath(store);
// 调用的实际是我们自定义的dispatch函数
// store.dispatch(addAction);
store.dispatch(getUserInfo);
- 根据判断action返回的对象还是函数来做处理
- 如果是对象直接执行
- 如果是函数,参数传入两个参数dispatch、getState