• Redux详解(一)


    1. Redux的作用

    React是在视图层帮助我们解决了DOM的渲染过程,但是State依然是留给我们自己来管理:
    • 无论是组件定义自己的state,还是组件之间的通信通过props进行传递;也包括通过Context进行数据之间的共享;
    • React主要负责帮助我们管理视图,state如何维护最终还是我们自己来决定;
    Redux就是帮助react管理state的容器Redux是 JavaScript的状态容器 ,提供了 可预测的状态管理;
    Redux是一个独立的npm库,并不只能适用于React,也可以与其他javaScript构建界面库使用,具有较高的灵活性,且小体积的特点;

    2. Redux核心理念 - Store

    对于多个页面共享的一个数据时,需要定义统一的规范来操作数据,才能使整个数据的变化可追踪;

    3. Redux核心理念 - action

    Redux要求我们通过action来更新数据:
    • 所有数据的变化,必须通过派发(dispatch)action来更新;
    • action是一个普通的JavaScript对象 ,用来描述这次 更新的type和content;
    • 强制使用action的好处是可以清晰的知道数据到底发生了什么样的变化,所有的数据变化都是可跟追、可预测的;
    • actions可以派发的是对象或者函数

    4. Redux核心理念 - reducer

    通过actions派发修改state状态的桥梁,就是reducer

    • reducer是一个纯函数;
    • reducer做的事情就是 将传入的state和action结合起来生成一个新的state;
    1. import * as actionsTypes from './constant'
    2. const initialState = {
    3. counter: 10
    4. }
    5. function reducer(state = initialState, actions) {
    6. switch(actions.type) {
    7. case actionsTypes.ADD_NUMBER:
    8. return {...state, counter: state.counter + actions.num}
    9. case actionsTypes.SUB_NUMBER:
    10. return {...state, counter: state.counter - actions.num}
    11. default:
    12. return state
    13. }
    14. }
    15. export default reducer

    5. Redux三大原则

    单一数据源:

    • 整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中;
    • Redux 并没有强制让我们不能创建多个Store ,但是 那样做并不利于数据的维护;
    • 单一的数据源 可以让整个应用程序的state变得 方便维护、追踪、修改;

    State是只读的:

    • 唯一修改State的方法一定是触发action不要试图在其他地方通过任何的方式来修改State;
    • 这样就确保了View或网络请求都 不能直接修改state ,它们只能 通过action来描述自己想要如何修改state;
    • 可以 保证所有的修改都被集中化处理 ,并且 按照严格的顺序来执行 ,所以 不需要担心race condition(竟态)的问题;
    使用纯函数来执行修改:
    • 通过reducer将 旧state和 actions联系在一起,并且返回一个新的State;
    • 随着 应用程序的复杂度增加 ,我们 可以将reducer拆分成多个小的reducers 分别操作不同state tree的一部分;
    • 所有的reducer都应该是纯函数 ,不能产生任何的副作用;

    6. Redux使用过程

    1. 建一个对象,作为我们要保存的状态;

    2. 创建Store来存储这个state;

    • 创建store时必须创建reducer;
    • 可以通过 store.getState 来获取当前的state;
    3.  过action来修改state;
    • 通过dispatch来派发action;
    • 通常action中都会有type属性,也可以携带其他的数据;
    4.  改reducer中的处理代码;
    • reducer是一个纯函数,不需要直接修改state;

    5. Redux结构划分;

    将所有的逻辑代码写到一起,那么当redux变得复杂时代码就难以维护。
    分为以下几个文件模块

    constant.js 定义type的常量

    1. export const ADD_NUMBER = "add_number"
    2. export const SUB_NUMBER = "sub_number"

    createActions.js dispatch派发的actions, 返回一个对象

    1. import * as actionsType from './constant'
    2. export const addNumberActions = (num) => ({
    3. type: actionsType.ADD_NUMBER,
    4. num
    5. })
    6. export const subNumberActions = (num) => ({
    7. type: actionsType.SUB_NUMBER,
    8. num
    9. })

    reducer.js 处理派发的actions,返回新的state 实现state状态更新

    1. import * as actionsTypes from './constant'
    2. const initialState = {
    3. counter: 10
    4. }
    5. function reducer(state = initialState, actions) {
    6. switch(actions.type) {
    7. case actionsTypes.ADD_NUMBER:
    8. return {...state, counter: state.counter + actions.num}
    9. case actionsTypes.SUB_NUMBER:
    10. return {...state, counter: state.counter - actions.num}
    11. default:
    12. return state
    13. }
    14. }
    15. export default reducer

    index.js 导出reducer 

    1. import reducer from "./reducer";
    2. export default reducer
    3. export * from "./createActions"

    创建store

    1. import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
    2. import thunk from 'redux-thunk'
    3. import counterReducer from './features/counter'
    4. import homeReducer from './features/home'
    5. import userInfoReducer from './features/userInfo'
    6. const reducer = combineReducers({
    7. counter: counterReducer,
    8. home: homeReducer,
    9. userInfo: userInfoReducer
    10. })
    11. // 打开 redux-devtools {trace: true} 追踪代码执行
    12. const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
    13. const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
    14. export default store

    7. Redux使用流程

    注意:此图出自coderwhy老师的react课程讲解,有兴趣的小伙伴可以腾讯课堂搜索why老师课程学习

    Redux官方文档对于Redux更新state的流程图表述:

    8. Redux融入react使用

    以counter数加减实现来说
    核心代码主要是两个:
    • 在 componentDidMount 中定义数据的变化,当数据发生变化时重新设置 counter;
    • 在发生点击事件时,调用store的dispatch来派发对应的action;
    8.1 react-redux使用

    前文开头强调redux和react没有直接的关系,在React, Angular, Ember, jQuery, or vanilla JavaScript也完全可以使用Redux。

    React官方为了在项目中更高效的使用redux,redux官方提供了react-redux库

    npm install react-redux

    1. import { Provider } from 'react-redux'
    2. import store from "./store"
    3. const root = ReactDOM.createRoot(document.querySelector("#root"))
    4. root.render(
    5. <Provider store={store}>
    6. <App/>
    7. Provider>
    8. )

    组件中:

    1. import React, { PureComponent } from 'react'
    2. import { connect } from 'react-redux'
    3. import { addNumberActions, subNumberActions } from '../../store/features/counter'
    4. export class About extends PureComponent {
    5. calcNumber(num, isAdd) {
    6. if(isAdd) {
    7. this.props.addNumber(num)
    8. } else {
    9. this.props.subNumber(num)
    10. }
    11. }
    12. render() {
    13. const { counter, banners, recommends } = this.props
    14. return (
    15. <div>
    16. <h2>About: counter: {counter}h2>
    17. <div>
    18. <button onClick={e =>this.calcNumber(5, true)}>+5button>
    19. <button onClick={e =>this.calcNumber(5, false)}>-5button>
    20. div>
    21. <div>
    22. <h2>banners数据:h2>
    23. <ul>
    24. {
    25. banners.map((item, index) => {
    26. return <li key={index}>{item.title}li>
    27. })
    28. }
    29. ul>
    30. div>
    31. <div>
    32. <h2>recommends数据:h2>
    33. <ul>
    34. {
    35. recommends.map((item, index) => {
    36. return <li key={index}>{item.title}li>
    37. })
    38. }
    39. ul>
    40. div>
    41. div>
    42. )
    43. }
    44. }
    45. const mapStateToProps = (state) => ({
    46. counter: state.counter.counter,
    47. banners: state.home.banners,
    48. recommends: state.home.recommends
    49. })
    50. const mapDispatchToProps = (dispatch) => ({
    51. addNumber(num) {
    52. dispatch(addNumberActions(num))
    53. },
    54. subNumber(num) {
    55. dispatch(subNumberActions(num))
    56. }
    57. })
    58. export default connect(mapStateToProps, mapDispatchToProps)(About)
    8.2 组件中的异步操作

    对于网络请求中的数据,需要交给redux来处理,需要通过中间件(middleware)来实现

    理解中间件:

    • 中间件的目的是在dispatch的action和最终达到的reducer之间,扩展一些自己的代码;
    • 比如 日志记录、调用异步接口、添加代码调试功能 等等;
    对于发送异步的网络请求,通过 官网推荐的、包括演示的网络请求的中间件是使用 redux-thunk
    • 默认情况下的dispatch(action),action需要是一个JavaScript的对象;
    • redux-thunk可以让dispatch(action函数),action可以是一个函数;
    • 该函数会被调用,并且会传给 这个函数一个 dispatch函数和getState函数
      • dispatch函数 用于我们之后再次派发action;
      • getState函数 考虑到我们之后的一些操作需要依赖原来的状态,用于让我们可以获取之前的一些状态;

    npm install redux-thunk

    const store = createStore(reducer, applyMiddleware(thunk))
    1. export const fetchHomeMultidataActions = () => {
    2. return (dispatch, getData) => {
    3. axios.get('http://123.207.32.32:8000/home/multidata').then(res => {
    4. const banners = res.data.data.banner.list
    5. const recommends = res.data.data.recommend.list
    6. dispatch(changeBannersActions(banners))
    7. dispatch(changeRecommendsActions(recommends))
    8. })
    9. }
    10. }
    8.3 store的模块化分
    目前我们合并的方式是通过每次调用reducer函数自己来返回一个新的对象,事实上,redux给我们提供了一个 combineReducers函数 可以方便的让我们对多个reducer进行合并:
    1. import { createStore, applyMiddleware, compose, combineReducers } from 'redux'
    2. const reducer = combineReducers({
    3. counter: counterReducer,
    4. home: homeReducer,
    5. userInfo: userInfoReducer
    6. })
    combineReducers实现原理
    • 将我们传入的reducers合并到一个对象中,最终返回一个combination的函数(相当于我们之前的reducer函数了);
    • 在执行combination函数的过程中,它会通过判断前后返回的数据是否相同来决定返回之前的state还是新的state;
    • 新的state会触发订阅者发生对应的刷新,而旧的state可以有效的组织订阅者发生刷新;​​​​​​​
  • 相关阅读:
    leetCode 70.爬楼梯 动态规划
    Bash变量--位置参数变量
    sql执行报错Truncated incorrect time value的解决方法
    Python学习笔记--类的访问控制
    flink1.15.0消费kafka 报错 The coordinator is not available.
    MVC第三波书店登录
    全网最详细解读《GIN-HOW POWERFUL ARE GRAPH NEURAL NETWORKS》!!!
    深入详解Mybatis的架构原理与6大核心流程
    Redis五种基本数据结构
    【Final Project】Kitti的双目视觉里程计(1)
  • 原文地址:https://blog.csdn.net/weixin_47342624/article/details/133812715