redux的基本使用
// 创建store容器
const store = Redux.createStore(reducer)
// 创建用于处理状态的reducer函数,dispatch时也会执行
function reducer(state) {
    ...
}
// 订阅状态,当状态修改是会触发回调
store.subscribe(() => {
    ...
})
// 触发action
store.dispatch({type: 'xxx'})安装react-redux
yarn add redux react-redux当触发action时,会调用reducer处理函数,reducer函数中处理完毕后,就会触发订阅回调
为什么要使用Redux
- 在React中组件通信的数据流是单向的,父组件可以通过props向子组件传递数据,子组件不能向父组件传递数据,修改父组件数据只能将修改的方法传递给子组件
- 使用Redux管理数据,Store独立与组件,解决了组件与组件间传递数据困难的问题
在项目中使用reudxreact-redux提供了Provider组件,通过Provider组件store传递给内部组件,是内部组件可以访问store中的内容
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux'
import App from './App.jsx';
import store from './store';
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
);import {connect} from 'react-redux'
function App(props) {
  return (
    <div className="App">
      count:{props.count}
    </div>
  );
}
const mapStateToProps = state=>({
  count: state.count
})
export default connect(mapStateToProps)(App);
connect中的第二个参数是可以让我们获取到dispatch方法(之前说过dispatch方法会触发action,最终会执行reducer函数)
...
const mapStateToProps = state=>({
  count: state.count
})
const mapDispatchToProps = dispatch =>({
  increment(){
    return dispatch({
      type: 'increment'
    })
  },
  decrement(){
    return dispatch({
      type: 'decrement'
    })
  }
})
export default connect(mapStateToProps, mapDispatchToProps)(App);
处理reducer
import {
    createStore
} from 'redux'
const initState = {
    count: 0
}
function reducer(state = initState, action) {
    switch(action.type){
        case 'decrement':
            return {
                count: state.count - 1
            };
        case 'increment':
            return {
                count: state.count + 1
            };
         default:
            return state
    }
}
const store = createStore(reducer)
export default store使用bindActionsCreators
import { bindActionCreators } from 'redux'
...
const mapDispatchToProps = dispatch => bindActionCreators({
  increment() {
    return {
      type: 'increment'
    }
  },
  decrement() {
    return {
      type: 'decrement'
    }
  }
}, dispatch)将mapDispatchToProps中的action提取到单独的文件中
// actions.js
export const increment = () => ({
    type: 'increment'
})
export const decrement = () => ({
    type: 'decrement'
})import * as countActions from './store/actions'
... 
const mapDispatchToProps = dispatch => bindActionCreators(countActions, dispatch)拆分多个reducer,当reducer中的代码比较多时,可以拆分进行管理
import {
    combineReducers
} from 'redux'
import countReducer from './count'
import showReducer from './show'
export default combineReducers({
    counter: countReducer,
    modal: showReducer
})// count.js
const initState = {
    count: 0
}
export default function countReducer(state = initState, action) {
    switch(action.type){
        case 'decrement':
            return {
                count: state.count + 1
            };
        case 'increment':
            return {
                count: state.count + 1
            };
         default:
            return state
    }
}在组件中使用
...
const mapStateToProps = state => ({
  count: state.counter.count,
  show: state.modal.show
})
const mapDispatchToProps = dispatch => bindActionCreators(countActions, dispatch)传递参数
export const increment = payload => ({
    type: 'increment',
    payload
})
export const decrement = payload => ({
    type: 'decrement',
    payload
})
export default function countReducer(state = initState, action) {
    switch (action.type) {
        case 'decrement':
            return {
                count: state.count - (action.payload ? action.payload : 1)
            };
        case 'increment':
            return {
                count: state.count + (action.payload ? action.payload : 1)
            };
        default:
            return state
    }
}<button onClick={() => props.decrement(5)}>-</button>redux的中间件
开发一个redux中间件
export default function logger(store) {
    return next => {
        return action => {
            console.log(action)
            next(action)
        }
    }
}引入中间件
import reducer from './reducers'
import {
    applyMiddleware
} from 'redux'
import logger from './middlewares/loggger'
const store = createStore(reducer, applyMiddleware(logger))
export default store开发一个支持异步操作的中间件
export default function thunk(store) {
    return next => {
        return action => {
          // 如果action是个函数,就执行这个函数
          // 并把dispatch传递过去
            if (typeof action === 'function') {
                return action(store.dispatch)
            }
            next(action)
        }
    }
}在异步action中,异步任务执行完成后,调用dispatch方法触发其他的action
export const deplay_increment = payload => dispatch => {
    setTimeout(() => {
        dispatch(increment(payload))
    }, 2000)
}...
const store = createStore(reducer, applyMiddleware(logger, thunk))
...redux-thunk
redux-thunk的使用方法和上面实现的thunk中间件的使用方法一样
...
import thunk from 'redux-thunk'
...
const store = createStore(reducer, applyMiddleware(logger,thunk))redux-actions
在上面的代码中,我们创建action,写了比较多的样本代码,甚至,还需要将action.type写成常量提取到单独的文件进行管理,这样增加了代码量
通过使用redux-actions可以简化这些过程
import {
    createAction
} from 'redux-actions'
export const decrement = createAction('decrement')
export const increment = createAction('increment')import {
    handleActions as createReducer
} from 'redux-actions'
import {
    decrement,
    increment
} from '../actions'
const countReducer = createReducer({
    [increment]: (state, action) => {
        return {
            count: state.count + (action.payload ? action.payload : 1)
        }
    },
    [decrement]: (state, action) => {
        return {
            count: state.count - (action.payload ? action.payload : 1)
        }
    }
}, initState)
export default countReducerredux-saga
redux-saga也是用来处理异步操作的,可以将要处理的异步操作放到单独的文件中
import {
    takeEvery,
    put,
    delay
} from 'redux-saga/effects'
import {
    deplay_increment,
    increment
} from '../actions'
// takeEvery  接收action
// put 触发action
// 处理
function* handleDelayIncrement(action) {
    yield delay(2000)
    // 触发action
    yield put(increment(action.payload))
}
export default function* CounterSaga() {
  // 接收action
    yield takeEvery(deplay_increment, handleDelayIncrement)
}引入redux-saga
import {
    createStore
} from 'redux'
import {
    applyMiddleware
} from 'redux'
import createSagaMiddleWare from 'redux-saga'
import reducer from './reducers'
import CounterSaga from './sagas/couter'
const sageMiddleWare = createSagaMiddleWare()
const store = createStore(reducer, applyMiddleware(sageMiddleWare))
sageMiddleWare.run(CounterSaga)
export default store合并多个saga,使用redux-saga/effects中all方法可以将多个saga文件进行合并
import {
    all
} from 'redux-saga/effects'
import counterSaga from './couter'
import modalSaga from './modal'
export default function* allSaga() {
    yield all([
        counterSaga(),
        modalSaga()
    ])
}Redux Toolkit
npm install @reduxjs/toolkit react-reduximport {
    createSlice,
    configureStore
} from '@reduxjs/toolkit'
export const TODOS_KEY = 'todos'
const {
    reducer: todoReducer,
    actions
} = createSlice({
    name: TODOS_KEY,
    initialState: [],
    reducers: {
        addTodo(state, actions) {
            state.push(actions.payload)
        }
    }
})export const {
    addTodo
} = actions
export default configureStore({
    reducer: {
        [TODOS_KEY]: todoReducer
    },
    devTools: process.env.NODE_ENV !== 'production'
}) 
                        
                        