LOADING...

加载过慢请开启缓存(浏览器默认开启)

loading

Redux

Redux介绍与基本使用

Redux介绍

Redux是React中使用广泛的集中状态管理工具 类比vuex之于vue 同类的工具还有mobx等

优点

  1. 独立于组件,无视组件之间的层级关系,简化通信问题
  2. 单项数据流清晰,易于定位bug
  3. 调试工具配套良好,方便调试

Redux数据流架构

  1. state: 一个对象 存放着我们管理的数据
  2. action: 一个对象 用来描述你想怎么改数据
  3. reducer: 一个函数 根据action的描述更新state

创建counterStore

创建store的的核心步骤分为两步

  1. 使用toolkit的createSlice方法创建一个独立的子模块
  2. 使用configureStore语法组合子模块

创建子模块

import { createSlice } from '@reduxjs/toolkit'

const counter = createSlice({
  // 模块名称独一无二
  name: 'counter',
  // 初始数据
  initialState: {
    count: 1
  },
  // 修改数据的同步方法
  reducers: {
    add (state) {
      state.count++
    }
  }
})

const { add } = counter.actions
const reducer = counter.reducer

// 导出修改数据的函数
export { add }
// 导出reducer
export default reducer

组合子模块

import { configureStore } from '@reduxjs/toolkit'

import counterStore from './counterStore'

export default configureStore({
  reducer: {
    // 注册子模块
    counterStore
  }
})

为React提供Redux store

要想让所有的组件都有资格访问store中的数据,需要我们在入口文件中,渲染根组件的位置通过Provider提供store数据

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
// 导入store
import store from './store'
// 导入store提供组件Provider
import { Provider } from 'react-redux'

ReactDOM.createRoot(document.getElementById('root')).render(
  // 提供store数据
  <Provider store={store}>
    <App />
  </Provider>
)

组件使用store中的数据

组件使用store中的数据需要借助一个hook方法,叫做useSelector

useSelector(state => state.模块名) 方法的返回值为一个对象,对象中包含store子模块中的所有数据

import { useSelector } from 'react-redux'

function App () {
  // 使用数据
  const { count } = useSelector(state => state.counterStore)
  
  return (
    <div className="App">
      {count}
      <button onClick={clickHandler}>+</button>
    </div>
  )
}

export default App

组件修改store中的数据

修改store中的数据有俩个核心步骤

  1. 使用counterStore模块中导出的add方法创建action对象
  2. 通过dispatch函数以action作为参数传入完成数据更新
import { useSelector, useDispatch } from 'react-redux'
import { add } from './store/counterStore'

function App () {
  // 使用数据
  const { count } = useSelector(state => state.counterStore)
  // 修改数据
  const dispatch = useDispatch()
  const clickHandler = () => {
    // 1. 生成action对象
    const action = add()
    // 2. 提交action进行数据更新
    dispatch(action)
  }
  return (
    <div className="App">
      {count}
      <button onClick={clickHandler}>+</button>
    </div>
  )
}

export default App

组件修改数据并传参

改数据的方法中补充第二个参数action

import { createSlice } from "@reduxjs/toolkit"
const counterStore = createSlice({
  name: 'counter', // 独一无二不重复的名字语义化
  // 定义初始化的数据
  initialState: {
    taskList: ['react']
  },
  reducers: {
    // action为一个对象 对象中有一个固定的属性叫做payload 为传递过来的参数
    addTaskList (state, action) {
      state.taskList.push(action.payload)
    }
  }
})

// 生成修改数据的方法导出
const { addTaskList } = counterStore.actions
export { addTaskList }
// 生成reducer 导出 供index.js做组合模块
const reducer = counterStore.reducer

export default reducer

dispatch的时候传入实参

<button onClick={() => dispatch(addTaskList('vue'))}>addList</button>

Redux异步处理

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

const channelStore = createSlice({
  name: 'task',
  initialState: {
    channels: []
  },
  reducers: {
    setChannels (state, action) {
      state.channels = action.payload
    }
  }
})


// 创建异步
const { setChannels } = channelStore.actions
const url = 'http://geek.itheima.net/v1_0/channels'
// 封装一个函数 在函数中return一个新函数 在新函数中封装异步
// 得到数据之后通过dispatch函数 触发修改
const fetchChannelList = () => {
  return async (dispatch) => {
    const res = await axios.get(url)
    dispatch(setChannels(res.data.data.channels))
  }
}

export { fetchChannelList }

const reducer = channelStore.reducer
export default reducer
import { useEffect } from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { fetchChannelList } from './store/channelStore'

function App () {
  // 使用数据
  const { channels } = useSelector(state => state.channelStore)
  useEffect(() => {
    const action = fetchTaskList()
    dispatch(action)
  }, [dispatch])

  return (
    <div className="App">
      <ul>
        {channels.map(task => <li key={task.id}>{task.name}</li>)}
      </ul>
    </div>
  )
}

export default App
img_show