Day03-Redux

一、介绍

Redux是React最常用的集中状态管理工具,类似于Vue中的Vuex,可以独立于框架运行。

作用:通过集中管理的方式管理应用的状态。
在这里插入图片描述
为什么要使用Redux?

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

二、Redux快速体验

1. 纯Redux实现计数器

步骤:

  1. 定义一个reducer函数(根据当前想要做的修改返回一个新的状态
  2. 使用createStore方法传入reducer函数,生成一个store实例对象
  3. 使用store实例的subscribe方法订阅数据的变化(数据一旦变化,可以得到通知)
  4. 使用store实例的dispatch方法提交action对象触发数据变化(告诉reducer你想怎么改数据
  5. 使用store实例的getState方法获取最新的状态更新到视图中
<button id="decrement">-</button>
<span id="count">0</span>
<button id="increment">+</button>
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>

<script>
  // 1. 定义reducer函数
  // 作用: 根据不同的action对象,返回不同的新的state
  // state: 管理的数据初始状态
  // action: 对象 type 标记当前想要做什么样的修改
  function reducer (state = { count: 0 }, action) {
    // 数据不可变:基于原始状态生成一个新的状态
    if (action.type === 'INCREMENT') {
      return { count: state.count + 1 }
    }
    if (action.type === 'DECREMENT') {
      return { count: state.count + 1 }
    }
    return state;
  }

  // 2. 使用reducer函数生成store实例
  const store = Redux.createStore(reducer);

  // 3. 通过store实例的subscribe订阅数据变化
  // 回调函数可以在每次state发生变化的时候自动执行
  store.subscribe(() => {
    console.log('state变化了', store.getState());
    document.getElementById('count').innerText = store.getState().count;
  })

  // 4. 通过store实例的dispatch函数提交action更改状态
  const inBtn = document.getElementById('increment')
  inBtn.addEventListener('click', () => {
    // 增
    store.dispatch({
      type: 'INCREMENT'
    })
  })

  const dBtn = document.getElementById('decrement')
  dBtn.addEventListener('click', () => {
    // 减
    store.dispatch({
      type: 'DECREMENT'
    })
  })

  // 5. 通过store实例的getState方法获取最新状态更新到视图中

</script>

2. Redux数据流架构

在这里插入图片描述
Redux有三个核心概念:

  1. state:一个对象,存放着需要管理的数据
  2. action:一个对象,用来描述如何更改数据
  3. reducer:一个函数,根据action的描述更新state

三、Redux与React-环境准备

1. 配套工具

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

2. 配套基础环境

  1. 使用CRA快速创建React项目

    npx create-react-app react-redux

  2. 安装配套工具

    npm i @reduxjs/toolkit react-redux

  3. 启动项目

    npm run start

3. store目录结构设计

在这里插入图片描述

  1. 通常集中状态管理的部分都会创建一个单独的store目录
  2. 应用通常会有多个store模块,可以创建一个modules目录,在内部编写业务分类的子store
  3. store中的入口文件index.js的作用是组合modules中所有的子模块,并导出store

四、Redux与React-实现counter

1. 整体路径熟悉

在这里插入图片描述

2. 使用React Toolkit 创建 counterStore

// counterStore.js
import { createSlice } from "@reduxjs/toolkit";

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

// 解构actionCreater函数
const { increment, decrement } = counterStore.actions;
// 获取reducer函数
const counterReducer = counterStore.reducer;
// 以按需导出的方式导出actionCreater
export { increment, decrement };
// 以默认导出的方式导出counterReducer
export default counterReducer;
// index.js
import { configureStore } from "@reduxjs/toolkit";
import counterReducer from './modules/counterStore';

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

3. 为React注入store

react-redux负责把Redux和React连接起来,内置Provider组件通过store参数把创建好的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>
)

4. React组件使用store中的数据(useSelector)

const { count } = useSelector(state => state.counter);

5. React组件修改store中的数据(useDispatch)

// App.js
import { useDispatch, useSelector } from 'react-redux'
// 导入创建action对象的方法
import { increment, decrement } from './store/modules/counterStore';
function App () {
  const { count } = useSelector(state => state.counter);
  // 得到dispatch函数
  const dispatch = useDispatch();

  return (
    <div className="App">
      {/*调用dispatch提交action对象*/}
      <button onClick={() => dispatch(decrement())}>-</button>
      {count}
      <button onClick={() => dispatch(increment())}>+</button>
    </div>
  )
}
export default App;

五、Redux与React-提交action传参

// counterStore.js
reducers: {
  increment(state) {
    state.count++;
  },
  decrement(state) {
    state.count--;
  },
  addToNum(state, action) {
    state.count = action.payload;
  }
}

// App.js
<button onClick={() => dispatch(addToNum(10))}>add to 10</button>
<button onClick={() => dispatch(addToNum(20))}>add to 20</button>

六、Redux与React-异步action处理

// channelStore.js
import { createSlice } from "@reduxjs/toolkit";
import axios from 'axios'

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

// 异步请求部分
const { setChannelList } = 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(setChannelList(res.data.data.channels))  }
}

const channelReducer = channelStore.reducer;

export { fetchChannelList };
export default channelReducer;
// App.js
import { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { fetchChannelList } from './store/channelStore';

function App () {
  // 使用数据
  const { channelList } = useSelector(state => state.channel);
  useEffect(() => {
    dispatch(fetchChannelList());
  }, [dispatch]);

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

export default App

七、Redux调试-devtools

  • 浏览器插件:Redux DevTools
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值