likes
comments
collection
share

花几分钟通篇回顾Redux(基础篇)

作者站长头像
站长
· 阅读数 23

Redux核心思想

  1. Redux 是一个 JavaScript 状态管理库,被广泛用于构建用户界面和处理应用程序的状态。它的核心思想是单一数据源(Single Source of Truth)和状态不可变性(Immutability)。
  2. Redux 的单一数据源意味着整个应用程序的状态被存储在一个单一的 JavaScript 对象中,称为 "store"。这个 store 是不可变的,即一旦创建,就不能直接修改它的状态。所有的状态变化都需要通过发起一个称为 "action" 的简单对象来描述。
  3. Redux 遵循一个严格的数据流向模式,这个模式被称为 "Flux" 架构。当应用程序的状态需要更新时,开发者需要 dispatch(派发)一个 action 到 Redux store。然后,Redux 根据 action 的类型和附带的数据来计算新的状态,并用新的状态替换旧的状态。
  4. 这种通过派发 action 和计算新状态的过程是纯函数式的,也就是说,它完全根据输入的数据来计算输出的结果,没有任何副作用。这种函数式的设计使得 Redux 在应用程序开发中具有可预测性和可测试性。
  5. 另一个核心思想是使用纯函数来处理状态的变化,这些函数被称为 "reducers"。Reducer 接收先前的状态和一个 action,返回一个新的状态。通过将这些 reducer 组合在一起,我们可以构建一个复杂的状态管理系统。
  6. Redux 还支持 "middleware",用于在处理 action 和 reducer 之间添加自定义的逻辑。这使得开发者可以在应用程序中处理异步操作、日志记录、错误处理等。
  7. 总而言之,Redux 的核心思想是通过一个单一的不可变状态来管理应用程序的状态,并使用纯函数式的方式处理状态的变化。这种设计模式使得状态管理更加可控、可预测,并且易于测试。

Redux基本使用

创建 Redux store

1)引入createStore2)初始化数据3)定义reducer函数(纯函数)4)创建store

const { createStore } = require('redux')
// 初始化数据
const initState = {
  name: 'colin',
  age: 21
}
// 定义reducer函数:纯函数
function reducer() {
  return initState
}
// 创建store
const store = createStore(reducer)
module.exports = store 
  • 使用store(使用node跑一下)
const store = require('./store');
console.log(store.getState())

花几分钟通篇回顾Redux(基础篇)

修改store的数据

1)新创建一个changeStore文件写修改方式

const store = require('./store');//先拿store
//修改1
const nameAction1 = { type: "change_name", name: "colin1" }
store.dispatch(nameAction1) //派发
console.log(store.getState())
//修改2
const nameAction2 = { type: "change_age", age: 18 }
store.dispatch(nameAction2) //派发
console.log(store.getState())

2)在reducer函数里做修改

// 定义reducer函数:纯函数
// 接收两个参数,(1)store目前保存的值 (2)传入的action
// 返回值:作为store之后存储的state
function reducer(state = initState, action) {
  // 有新数据进行更新,返回新的state
  // 没有 返回之前的state
  if (action.type === 'change_name') {
    return { ...state, name: action.name } //第一次修改name (nameAction1)
  } else if (action.type === 'change_age') {
    return { ...state, age: action.age } //第二次修改age (nameAction2)
  }
  return initState
}

花几分钟通篇回顾Redux(基础篇)

store数据订阅和reducer优化判断

1)通过订阅拿数据

store.subscribe(() => {
  console.log('订阅', store.getState());
})

2)优化reducer

function reducer(state = initState, action) {
  // 有新数据进行更新,返回新的state
  // 没有 返回之前的state
  switch (action.type) {
    case 'change_name':
      return { ...state, name: action.name }
    case 'change_age':
      return { ...state, age: action.age }
    default:
      initState
  }
}

代码重构-优化

1)重构action -> 函数式

const store = require('./store');

store.subscribe(() => {
  console.log('订阅', store.getState());
})
// actionCreators 帮助我们创建action
const changeNameAction = (name) => ({
  type: 'change_name',
  name: name
})
const changeAgeAction = (age) => ({
  type: 'change_age',
  age: age
})
const nameAction1 = changeNameAction('colin1')
const nameAction2 = changeNameAction('colin2')
store.dispatch(nameAction1)
store.dispatch(nameAction2)

const nameAction3 = changeAgeAction(18)
const nameAction4 = changeAgeAction(17)
store.dispatch(nameAction3)
store.dispatch(nameAction4)

React结合Redux

详细请看我这次代码提交

创建store文件夹,初始化index.js、reducer.js

import { createStore } from "redux";
import reducer from "./reducer";

const store = createStore(reducer)

export default store
const initState = {
  count: 0
}

function reducer(state = initState,action){
  switch(action.type){
    default:
      return state
  }
}
export default reducer

组件中引用(重构前需要每个文件都引用一次非常麻烦)

export class Main extends PureComponent {
  componentDidMount() {
    store.subscribe(() => {
      const state = store.getState()
      this.setState({ counter: state.count }) //订阅:更新即变化
    })
  }
  constructor() {
    super()
    this.state = {
      counter: store.getState().count //初始化counter
    }
  }
  render() {
    const { counter } = this.state
    return (
      <div>
        <h2>Main counter: {counter}</h2>
        <div className='pages'>
          <Home /> //子组件
          <Profile />//子组件
        </div>
      </div>
    )
  }
}

定义 Action 类型(Types):

export const ADD_NUMBER = 'add_number';
export const SUB_NUMBER = 'sub_number';

创建Action创建函数(Action Creator)

import * as actionTypes from './constants';
export const addNumberAction = (num) =>({
  type:actionTypes.ADD_NUMBER,
  num
})
export const subNumberAction = (num) =>({
  type:actionTypes.SUB_NUMBER,
  num
})

创建reducer

function reducer(state = initState, action) {
  switch (action.type) {
    case actionTypes.ADD_NUMBER:
      return { ...state, count: state.count + action.num }
    case actionTypes.SUB_NUMBER:
      return { ...state, count: state.count - action.num }
    default:
      return state
  }
}

组件内使用

 addNumber(num) {
    store.dispatch(addNumberAction(num))//派发
}
 render() {
    const { count } = this.state
    return (<div>
      <div>Home count: {count}</div>
      <div style={{ marginTop: 20 + 'px' }}>
        <button onClick={() => this.addNumber(1)}>+1</button>
        <button onClick={() => this.addNumber(3)}>+3</button>
        <button onClick={() => this.addNumber(5)}>+5</button>
      </div>
    </div>
    )
  }

react-redux

provider

在应用程序的入口文件中,创建 Redux store 并将其提供给应用程序。使用 Redux 的 createStore 函数创建 store,并使用 react-redux 的 Provider 组件将 store 包裹在应用程序的顶层组件外部。例如:

root.render(
  <Provider store={store}>
    <App />
  </Provider>
)

connect

在需要访问 Redux store 中的状态或触发 action 的组件中,使用 react-redux 的 connect 函数来连接组件与 Redux store。在组件的文件中,导入需要连接的组件以及需要从 store 中获取的状态和需要派发的 action。然后,使用 connect 函数将组件与 Redux store 进行连接,并导出连接后的组件。例如:

import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
export class About extends PureComponent {
  render() {
    const { count } = this.props
    return (
      <div>About:{count}</div>
    )
  }
}

function fn(state) {
  return {
    count: state.count
  }
}
export default connect(fn)(About)

组件和dispatch连接起来

export class About extends PureComponent {
  click(num) {
    if (num >= 0) {
      this.props.addNumber(num) //这里能拿到fn2的方法并传值
    } else {
      this.props.subNumber(num)
    }
  }
  render() {
    const { count } = this.props
    return (<div>
      <div>About:{count}</div>
      <div style={{ marginTop: 20 + 'px' }}>
        <button onClick={() => this.click(100)}>+100</button>
        <button onClick={() => this.click(-50)}>-50</button>
      </div>
    </div>
    )
  }
}
function fn2(dispatch) { //这里dispatch
  return {
    addNumber(num) {
      dispatch(addNumberAction(num))
    },
    subNumber(num) {
      dispatch(subNumberAction(num))
    }
  }
}
function fn(state) {
  return {
    count: state.count
  }
}
export default connect(fn, fn2)(About)

Redux的异步操作

具体可以看我这次代码提交记录

第一种:异步请求和保存数据到state(组件内:不太合适)

参考React结合Redux(创建变量、创建action creator、书写reducer)

// reducer
function reducer(state = initState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_BANNERS:
      return { ...state, banners: action.banners }
    case actionTypes.CHANGE_RECOMMENDS:
      return { ...state, recommends: action.recommends }
    default:
      return state
  }
}
// 创建变量
export const CHANGE_BANNERS = 'change_banners'
export const CHANGE_RECOMMENDS = 'change_recommends'
// 创建action creator
export const changeBannersAction = (banners) => ({
  type: actionTypes.CHANGE_BANNERS,
  banners
})

export const changeRecommendsAction = (recommends) => ({
  type: actionTypes.CHANGE_RECOMMENDS,
  recommends
})

发送请求获取数据->更改state数据(dispatch)

import axios from 'axios'
import React, { PureComponent } from 'react'
import { connect } from 'react-redux';
import store from '../../store'
import { changeBannersAction, changeRecommendsAction } from '../../store/actionCreators'

export class Category extends PureComponent {
  componentDidMount() {
    axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
      const banners = res.data.data.banner.list
      const recommends = res.data.data.recommend.list
      console.log(banners, recommends);
      //第一种写法
      // store.dispatch(changeBannersAction(banners))
      // store.dispatch(changeRecommendsAction(recommends))
      // 第二种写法 用 mapDispatchProps()
      this.props.changeBanners(banners)
      this.props.changeRecommends(recommends)
    })
  }
  render() {
    return (<div>
      <div>Category</div>

    </div>
    )
  }
}
function mapDispatchProps(dispatch) {
  return {
    changeBanners(banners) {
      dispatch(changeBannersAction(banners))
    },
    changeRecommends(recommends) {
      dispatch(changeRecommendsAction(recommends))
    }
  }
}
// 第一个函数没有 直接传null 必须传
export default connect(null, mapDispatchProps)(Category);

另一个组件借用数据

import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { addNumberAction, subNumberAction } from '../../store/actionCreators';
export class About extends PureComponent {
  render() {
    const {  banners, recommends } = this.props
    return (<div>
      <div className='banner'>
        <span>轮播图数据</span>
        <ul>
          {banners.map((v, index) => {
            return <li key={index}>{v.title}</li>
          })}
        </ul>
      </div>
      <div className='recommend'>
        <span>推荐数据</span>
        <ul>
          {recommends.map((v, index) => {
            return <li key={index}>{v.title}</li>
          })}
        </ul>
      </div>
    </div>
    )
  }
}
function fn(state) {
  return {
    count: state.count,
    banners: state.banners,
    recommends: state.recommends
  }
}
export default (fn)(About)

第二种:异步请求redux-thunk (redux内 :合适)

具体可以参考我这此代码提交(点击)

安装 Redux Thunk: 首先,使用 npm 或 yarn 安装 Redux Thunk 中间件:

npm install redux-thunk  //有了这个东西 我们就可以 让dispatch接收派发一个函数而不仅仅是一个对象
// 那我们不就可以异步请求了吗? 我们将这个函数作为返回值一并传给组件

应用 Redux Thunk 中间件: 在创建 Redux store 时,使用 Redux 的 applyMiddleware 函数将 Redux Thunk 中间件应用于 store。例如:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';

const store = createStore(rootReducer, applyMiddleware(thunk));

创建Action函数

export const fetchHomeMultidataAction = () => {
  return function foo(dispatch, getState) { //两个参数
    axios.get("http://123.207.32.32:8000/home/multidata").then(res => {
      const banners = res.data.data.banner.list
      const recommends = res.data.data.recommend.list
      dispatch(changeBannersAction(banners)) //派发
      dispatch(changeRecommendsAction(recommends))
    })
  }
}

调用Action

const mapDispatchProps = (dispatch) => ({
    fetchHomeList(){
      dispatch(fetchHomeMultidataAction())
    }
})

redux-devtool

Edge安装地址

开启(store文件夹下inde.js文件)

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
// 如果有中间件 包裹起来
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))

reducer的模块拆分

当应用程序变得复杂时,将reducer拆分成多个模块可以更好地组织代码。这可以通过使用Redux提供的combineReducers函数来实现。以下是一个示例,展示了如何在模块之间划分reducer:

首先,创建一个名为reducers.js的文件,用于存放所有的reducer模块

import { combineReducers } from 'redux';
import counterReducer from './counterReducer';
import todosReducer from './todosReducer';
import userReducer from './userReducer';

const rootReducer = combineReducers({
  counter: counterReducer,
  todos: todosReducer,
  user: userReducer,
});

export default rootReducer;

创建每个reducer模块的文件。例如,创建一个名为counterReducer.js的文件,其中包含与计数器相关的reducer逻辑。


import { INCREMENT, DECREMENT } from './actionTypes';

const initialState = {
  count: 0,
};

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT:
      return {
        ...state,
        count: state.count + 1,
      };
    case DECREMENT:
      return {
        ...state,
        count: state.count - 1,
      };
    default:
      return state;
  }
};

export default counterReducer;
同样地,创建其他reducer模块的文件,并实现相应的reducer逻辑。

最后,将rootReducer导入到应用程序的store.js文件中,并使用combineReducers函数来组合所有的reducer模块。

javascript
Copy code
// store.js

import { createStore } from 'redux';
import rootReducer from './reducers';

const store = createStore(rootReducer);

export default store;

最后将rootRedycer导入到应用程序的store.js文件,并使用combineReducers函数来组合所有reducer模块

import { createStore } from 'redux';
import rootReducer from './reducers';

const store = createStore(rootReducer);

export default store;

通过以上步骤,您可以将reducer划分为多个模块,并在应用程序中使用rootReducer来创建Redux store。每个模块可以独立处理特定的状态,并通过combineReducers将它们组合在一起,形成一个根级的reducer函数。

转载自:https://juejin.cn/post/7243612658519294007
评论
请登录