2025-09-17 第七天:Redux、ZuStand

一、独立使用Redux

1. 关于Redux

(1)Redux是React最常用的集中状态管理工具,可独立于React框架运行。

2. 使用步骤

(1)定义一个 \color{red}{reducer函数}。(根据当前想要做的修改返回一个 新的状态
(2)使用 createStore 方法 并传入 reducer函数,生成一个 \color{red}{store实例对象}
(3)使用 store实例对象的 \color{red}{subscribe方法} 订阅数据的变化。(数据变化时会触发此方法)
(4)使用 store实例对象的 \color{red}{dispathch方法} 传入 \color{red}{action对象},触发数据变化。(通过action对象告诉reducer你想调用哪个方法去修改数据)
(5)使用 store实例对象的 \color{red}{getState方法} 获取最新的状态数据。

3. Redux把整个数据修改流程分为三个核心概念

(1)state:一个对象,存放着公共数据状态。
(2)action:一个对象,用于描述想要怎么修改数据。
(3)reducer:一个函数,根据action的描述生成一个新的state。修改state数据的方法都在这里。

function reducer(state={},action){
  if(action.type==='1'){}
  if(action.type==='2){}
}

  • reducer函数有两个参数,第一个是 state数据,可以赋默认值;第二个是 action对象,可以根据type属性来区分不同的操作。
  • Redux中修改数据的唯一方法就是 提交一个action对象
  • 在reducer函数中修改state数据时,必须用 新的数据 替换旧的state数据,比如新的对象、新的数组。
<body>
    <button onclick="handleASC()">+</button>
    <button onclick="handleDESC()">-</button>

    <script src="https://unpkg.com/redux@4.2.1/dist/redux.js"></script>
    <script>
        // 1.定义reducer函数,根据传入的action对象,返回不同的新的state数据
        // 参数state:  管理的数据的初始状态
        // 参数action对象:根据type属性确定想要哪种操作
        function reducer(state = { count: 0 }, action) {
            if (action.type === 'ASC') {
                return { count: state.count + 1 } // 返回新的state数据
            } else if (action.type === 'DESC') {
                return { count: state.count - 1 }
            } else {
                return state
            }
        }

        // 2.使用createStore方法,传入reducer函数,生成store实例
        const store = Redux.createStore(reducer)

        // 3.使用store实例对象的subscribe方法订阅数据变化
        store.subscribe(() => {
            // 5.根据store实例对象的getState方法获取到最新的state数据
            console.log(store.getState())
        })

        // 4.使用store实例对象的dispatch方法,传入action对象来更新state数据
        const handleASC = () => {
            store.dispatch({ type: 'ASC' })
        }
        const handleDESC = () => {
            store.dispatch({ type: 'DESC' })
        }
    </script>
</body>

二、在React项目中使用Redux:准备工作

1. 安装必要插件

(1)React Toolkit:官方推荐编写Redux逻辑的方式,是一套工具的集合,可以 简化书写方式
(2)react-redux:连接 Redux 和 React组件 的中间件。

2. 创建目录

(1)在src目录下创建一个名为 store 的文件夹,包含 modules文件夹index.js 文件。
(2)index.js文件的作用是整合modules中的模块化文件,并导出 根store 实例对象。

三、在React项目中使用Redux:模块化开发

1. Redux子模块文件配置

(1)通过 createSlice方法 创建一个 子模块的 store实例对象
(2)配置项 name模块名称,配置项 initialState 对象用来存放 初始化的state数据
(3)配置项 reducers 对象存放修改数据的 \color{red}{同步方法}
   ① 同步方法的第一个参数是state,可以 访问state数据
   ② 同步方法的第二个参数是action,通过 action.payload 属性可以 获取自定义参数
(4)通过store实例对象的 actions 属性,获取 \color{red}{创建action对象的方法}\color{red}{方法名}和reducers中修改数据状态的方法同名,并按需导出。\color{green}{(React组件调用dispatch方法时要用)}
(5)通过store实例对象的 reducer 属性获取 子模块的reducer,并默认导出。\color{green}{(模块化配置时要用)}

import { createSlice } from '@reduxjs/toolkit'

// 1.通过createSlice方法创建一个store子模块实例对象
const countStore = createSlice({
  // 2.1模块名称
  name: 'counter',
  // 2.2初始化state数据
  initialState: {
    value: 100,
  },
  // 2.3修改state数据状态的方法,同步方法,可以直接修改数据
  reducers: {
    // 不传参
    increment: (state) => {
      state.value = state.value + 1
    },
    // 传参
    addNum: (state, action) => {
      state.value = state.value + action.payload
    }
  }
})

// 3.获取actionCreater方法,调用这个方法可以生成action,React组件中调用dispatch方法时,传入的参数就是action对象
const { increment, addNum} = countStore.actions
// 4.获取reducer
const counterReducer = countStore.reducer

export { increment, addNum }
export default counterReducer
2. Redux入口文件配置

(1)在store入口文件index.js中,通过 configureStore方法 创建 根store实例对象
(2)在 reducer配置对象 中配置子模块。\color{green}{key是子模块名称,value是子模块默认导出的reducer。}

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './modules/counterStore.js' // 导入子模块的reducer

// 1.通过configureStore创建 根store
const store = configureStore({
  // 2配置子模块的reducer
  reducer: {
    counter: counterReducer // 子模块名为counter
  }
})

export default store;
3. 全局挂载Redux

(1)在项目入口文件index.js中导入 根store实例Provider
(2)用Provider包裹 项目根组件 <App/> 或者是路由组件 <RouterProvider></RouterProvider>,将store传入。

import store from './store'  // 1.导入根store实例对象
import { Provider } from 'react-redux'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
4. 在React组件中使用Redux数据和方法

(1)通过 useSelector 获取模块化的 store数据

const res = useSelector((state) => state.子模块名称)

(2)通过 useDispatch 生成 dispatch

const dispatch = useDispatch()

(3)用dispatch调用 修改store数据的方法,入参是一个 action对象\color{red}{生成action对象的方法要从store子模块中导入。}

dispatch(生成action对象的方法())

import { useSelector, useDispatch } from "react-redux";
import {increment, addNum} from './store/modules/counterStore' // 1.导入生成action对象的方法

function App() {
  const res = useSelector((state) => state.counter) // 2.获取store数据
  const dispatch = useDispatch() // 3.生成dispatch
  return (
    <div className="App">
      <span>{ res.value }</span>
      <button onClick={() => dispatch(increment())}>点击自增1</button>
      <button onClick={()=> dispatch(addNum(20))}>点击自增20</button>
    </div>
  );
}

export default App;
5. 异步操作

(1)如果要进行异步操作,则在前面四步的基础上做进一步处理。
(2)reducers中的同步方法可以 直接修改 state数据;异步操作要调用reducers的同步方法,间接修改 state数据。
(3)在store子模块中,单独封装一个函数,函数内部 return 一个新函数,在新函数中:
   ① 封装异步请求获取数据。
   ② 用dispatch调用同步方法并传递数据,dispatch从 新函数的形参 获取。
(4)React组件中的调用方式不变。

import { createSlice } from '@reduxjs/toolkit';
import axios from 'axios'

const channelStore = createSlice({
  name: 'channel',
  initialState: {
    value: []
  },
  reducers: {
    setValue(state, action) {
      state.value = action.payload
    }
  }
})

const { setValue } = channelStore.actions
const channelReducer = channelStore.reducer

// 封装异步操作
const getChannelList = () => {
  return async (dispatch) => {
    const res = await axios.get('http://geek.itheima.net/v1_0/channels') // 1.异步操作
    dispatch(setValue(res.data.data.channels)) // 2.调用reducers的同步方法,并传递参数
  }
}
export { getChannelList }
export default channelReducer

四、ZuStand的基本使用

1. 关于ZuStand

(1)ZuStand是一个全局状态管理工具,拥有基于 hooks 的舒适的API。
(2)安装:npm install zustand

2. 项目中使用

(1)在store入口文件中,使用 create 函数创建 useStore函数,接收一个回调函数作为参数。
(2)回调函数接收一个 set 参数;回调函数返回一个对象,存放 state数据修改state数据的方法
(3)修改数据时,必须在方法内部调用 set 函数进行修改,通过 state 参数访问state数据。

const 实例对象名 = create((set)=>{return {
 数据名:数据值,
 方法名:(自定义参数)=>set((state)=>({数据名:state.数据名 + 1}))
}})

import { create } from 'zustand'

const useStore = create((set) => {
  return {
    // 1.初始化的数据
    number: 0,     
    // 2.修改数据的方法。newNumber为参数; state可以访问到state数据; 修改数据必须调用set方法
    setNumber1: (newNumber) => set((state) => ({ number: state.number + newNumber })), 
    // 3.异步操作直接写到方法内部即可
    setNumber2: (newNumber) => {
      setTimeout(() => {     
        set(state=>({number: state.number - newNumber}))
      },1000)
    }
  }
})

export default useStore

(4)React组件中使用,引入store模块创建的 useStore函数,从中获取到state数据和修改state数据的方法。

import useStore from './store/index.js'

function fn(){
  const {number, setNumber1, setNumber2} = useStore() // 调用useStore函数,获取数据和方法
  return <button onClick={()=>setNumber1(100)}>{number}</button>
}
3. 项目中模块化使用

(1)store子模块

const channelStore = (set) => {
  return {
    // 1.初始化的数据
    number: 0,
    // 2.修改数据的方法。newNumber为参数; state可以访问到state数据; 修改数据必须调用set方法
    setNumber1: (newNumber) => set((state) => ({ number: state.number + newNumber })),
    // 3.异步操作直接写到方法内部即可
    setNumber2: (newNumber) => {
      setTimeout(() => {
        set(state=>({number: state.number - newNumber}))
      },1000)
    }
  }
}

export default channelStore

(2)store入口文件

import { create } from 'zustand'
import channelStore from './modules/channel'

const useStore = create((...a) => {
  return {
    ...channelStore(...a),
  }
})

export default useStore

(3)React组件中使用方法不变,同上。

import useStore from './store/index.js'

function fn(){
  const {number, setNumber1, setNumber2} = useStore() // 调用useStore函数,获取数据和方法
  return <button onClick={()=>setNumber1(100)}>{number}</button>
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容