redux课程

news/2024/7/15 17:56:27 标签: javascript, react.js, 前端

课程说明

目的:为React移动端项目做支撑:redux、redux-thunk、react-redux(useDispatch、useSelector )、redux-devtools-extension

内容顺序(课程目标):

  1. redux单独使用
  2. react-redux 结合react项目进行使用
  3. 中间件react-thunk的基本使用
  4. useDispatch, useSelector的基本使用
  5. redux模块管理
  6. redux-devtools-extension

Redux基本介绍

基本介绍

概念

Redux 是 react 中最流行的状态管理工具之一 。

起源

React 只是 DOM 的一个抽象层(UI 库),并不是 Web 应用的完整解决方案。因此react在涉及到数据的处理以及组件之间的通信时会比较

  • 对于大型的复杂应用来说,这两方面恰恰是最关键的。因此,只用 React,写大型应用比较吃力。
  • 2014 年 Facebook 提出了 Flux 架构的概念,引发了很多的实现。
  • 2015 年,Redux 出现,将 Flux 与函数式编程(reducer)结合一起,很短时间内就成为了最热门的前端架构。
  • Flux 是最早的状态管理 工具,它提供了状态管理的思想,也提供对应的实现
  • 除了 Flux、Redux 之外,还有:Mobx 等状态管理工具

什么时候使用 redux

  • 如果你不知道是否需要 Redux,那就是不需要它。
  • 只有遇到 React 实在解决不了的问题,你才需要 Redux

为什么需要 redux

集中的方式统一管理所有的共享数据

react 技术栈

  • react 核心 react hooks
  • react-router(react-router-dom)
  • 状态管理: mobx(简单)/ redux(复杂) ----中间件: redux-thunk redux-saga

Redux基本使用

  • 单独讲解redux的使用
  • 不考虑代码模块化和优化,先掌握最基本的写法

redux介绍和安装

目标:了解redux的作用,并且完成安装

内容

  1. redux的作用:redux中文文档 redux官网(英文)
  2. redux安装(在react项目中)
npx create-react-app reduxstudy
cd reduxstudy
yarn start
yarn add redux
新建src/test.html 导入redux包    
<script src="../node_modules/redux/dist/redux.js"></script>
// 测试redux是否安装成功
console.log(window.Redux)

注意

  1. redux和react没有任何关系,是一个为JS应用程序提供的状态管理工具
  2. 关于在react中使用redux,后续会讲解

redux管理流程

目标:明确redux的状态管理流程

在这里插入图片描述

理解三个核心概念

  • 核心概念:storeactionreducer
    • store:仓库,存储了数据,管理者,管理 action 和 reducer
    • action:“专家”,只提想法不干活
    • reducer:劳动者,搬砖的人
store: redux的仓库
	1. 提供了state与操作state的方法
	2. 一个redux项目中,只有一个store
    3. 是整个redux应用的管理者,指挥action和reducer干活的
action: 表示一个动作(添加内容,删除内容等)
	1. action描述了需要做一件什么样的事情(不执行)
    2. "专家": 只提想法,不干活
reducer: 劳动者
	1. 根据action来完成这个动作
    2. 实际干活的人
    3. reducer不会主动完成action,需要store控制

redux-state初始数据

目标:在非react开发环境下先测试redux的基本用法,这里先准备数据state

内容:通过文档学习state的设计

要点:所有的 state 都被保存在一个单一对象中

核心代码

// test.html/script
const initState = {
  count:1
}

redux-action基本用法

目标:定义一个最基本的action

内容

  1. actions 只是描述了有事情发生了这一事实,而不是真正修改数据的位置
  2. action 是任务的抽象,视图中的每个用户交互都是一个 action,比如:添加任务、删除任务、登录、加入购物车 等
  3. Action 本质上是 JavaScript 普通对象
  4. action 内必须使用一个字符串类型的 type 字段来表示将要执行的动作
  5. action如果数量过多,将来会采用模块化管理的方式,这里先写简单的

核心代码

1. action是一个js对象
2. action必须提供type属性,表示动作的类型
3. type属性的值是一个字符串,采用全大写字母表示,多个单词使用_连接
{
	type: "INCREMENT"
}
4. action中除了type,还可以指定动作需要的其他数据
{
	type: "ADD_TODO",
	todoName: '学习redux'
}
5. 将来要完成的所有功能,都抽象成了一个个的动作

注意

  1. 以上是过程性代码,还没有写完,不能测试
  2. action的编写要点是记住各种规则

redux-action creator创建函数

目标:使用函数去创建一个action

内容

  1. 直接使用对象来创建action不灵活,参数写死了。一般会使用函数来创建action,我们把创建action的函数叫做actionCreator
  2. action creator创建函数只是简单的返回一个 action
  3. action creator创建函数的好处是更容易被移植和测试

核心代码

// test.html/script
const increment = {
    type: 'INCREMENT'
}
const increment = () => {
    return {
        type: 'INCREMENT'
    }
}
const increment = () => ({
    type: 'INCREMENT'
})

// 使用action创建函数:(添加任务)
const addTodo = {
    type: 'ADD_TODO',
    text: '加班'
}

const addTodo = (text) => ({
  type: 'ADD_TODO',
  text
})
addTodo('加班') // {type: '', text: ''}
addTodo('下课')

注意

  1. action创建函数只是为了易移植

redux-reducer函数

目标:state、action都书写完毕,但二者目前没任何关系,通过学习reducer将二者产生联系

内容

  1. Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的(reducer来根据 action 更新 state 的用法)
  2. reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state
  3. 不要在reducer函数内部直接修改state(纯函数的要求)
1. reducer需要是一个纯函数
2. reducer不能修改传入进来的参数(state),应该根据传入的参数返回新的数据(state)
3. 伪代码语法: (prevState, action) => newState   根据传入的状态和action,完成对应的动作,返回新的状态

注意:
	1. 在reducer中不能修改传入的state状态,保证数据的不可变性(immutability)
    2. 如果有reducer处理不了的任务,需要返回默认的state

核心代码

// 处理ADD_TODO动作的reducer:
const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      // 返回新的state
      return [
        ...state,
        {
          text: action.text,
          completed: false
        }
      ]
  }
  default:
    return state
}

注意

  1. 要保证reducer函数的传函数特点,不要直接修改state
  2. 遇到未知的 action 时,一定要返回旧的 state

reducer 纯函数的说明

  • 特点:只要是固定的输入,必定得到固定的输出
  • 原则:(一定要遵守!!!)
    • 不得改写参数
    • 不能调用 Date.now()或者 Math.random()等不纯的方法,因为每次会得到不一样的结果
    • 不能使用全局变量
  • 1 reducer 必须是一个纯函数
  • 2 纯函数主要的含义就是它不可以修改影响输入值
  • 3 没有副作用,副作用指的是例如函数中一些异步调用或者会影响函数作用域之外的变量一类的操作
let num = 1
// 不要进行以下操作:
function todos() {
  // 1 不要调用以下方法:
  // Date.now()
  // Math.random()
  //
  // 2 ajax 请求之类的操作
  //
  // 3 不要尝试修改作用域外的数据
  // num = 3
}

redux-store状态管理

目标:state、action、reducer都书写完毕,但目前三者还没联系,reducer函数没有调用,通过store进行使用打通数据管理

内容

  1. Store 是把actioin、reducer联系到一起的对象 => 利用Redux的API进行创建createStore()
  2. 提供 getState() 方法获取 state
  3. 提供 dispatch(action) 方法更新 state;
  4. 通过 subscribe(listener) 注册监听器;
  5. 通过 subscribe(listener) 返回的函数注销监听器。

核心代码

//   创建store
const { createStore } = window.Redux
//   createStore(reducer函数,可选=>state初始值)
let store = createStore(addReducer)
// 打印初始状态
console.log(store.getState()) // {count: 1}
// 每次 state 更新时,打印日志
// 注意 subscribe() 返回一个函数用来注销监听器
const unsubscribe = store.subscribe(() => console.log(store.getState()))

// 发起一系列 action
store.dispatch(add(2))
store.dispatch(add(4))
// 停止监听 state 更新
unsubscribe();

注意

  1. 注意代码顺序:先创建store,启动监听,修改数据时自动在监听里面获取最新数据
  2. 总结梳理整个流程

练习

内容

  1. 梳理每部分的职责和特点(作用是什么,怎么写)
  2. 按照+2的action,写-2的action(注意代码位置)

小结

  1. redux和react目前没有任何关系(结合redux应该怎么使用呢?后续)
  2. redux每部分的写法都是基础写法,没有考虑模块化和代码拆分等
  3. 纯函数,目前只需要知道的特点是不能直接修改数据
  4. 目前不考虑异步action的情况

react-redux(结合react和hooks)

  • 在react项目中如何使用redux

在react项目中使用redux

目标:在脚手架创建的react项目中使用最基本的redux

内容

  1. 把redux的基本代码该写在react项目中的对应文件
  2. 考虑代码的模块化和基本拆分

核心代码

store/actions.js

export const add = (count) => {
  return {
    type: 'ADD',
    count,
  }
}

store/reducers.js

export const addReducer = (
  state = {
    count: 1,
  },
  action
) => {
  switch (action.type) {
    case 'ADD':
      return Object.assign({}, state, { count: action.count })
    default:
      return state
  }
}

index.js

import ReactDOM from 'react-dom'
import App from './App.js'
import { createStore } from 'redux'
import { addReducer } from "./store/reducers"
let store = createStore(addReducer)
ReactDOM.render(<App store={store}></App>, document.querySelector('#root'))
store.subscribe(() => {
  ReactDOM.render(<App store={store}></App>, document.querySelector('#root'))
})

App.js

import { add } from './store/actions'
const App = (props) => {
  const {
    store: { getState, dispatch },
  } = props
  const { count } = getState()
  return (
    <div>
      <h3>App</h3>
      <p>{count}</p>
      <button
        onClick={() => {
          dispatch(add(2))
        }}
      >
        点我+2
      </button>
    </div>
  )
}

export default App

问题

  1. 确实做到了状态的声明和修改都交给了redux
  2. 但目前用redux似乎状态管理变得更加麻烦

react-redux包的基本使用

目标:使用react-redux简化redux在react项目中的使用

内容

  1. 介绍react-redux => yarn add react-redux
  2. 安装并且配置react-redux => 参考文档
  3. 优化刚才的代码

核心代码

store/store.js

import { createStore } from 'redux'
import { addReducer } from './reducers.js'
let store = createStore(addReducer)
export default store

store/reducers.js

export const addReducer = (
  state = {
    count: 1,
  },
  action
) => {
  switch (action.type) {
    case 'ADD':
      return Object.assign({}, state, { count: action.count })
    default:
      return state
  }
}

index.js

import ReactDOM from 'react-dom'
import App from './App.js'
import store from './store/store.js'
import { Provider } from 'react-redux'
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.querySelector('#root')
)

App.js

import { add } from './store/actions'
import { connect } from 'react-redux'
const App = (props) => {
  console.log(props)
  const { count, dispatch1 } = props
  return (
    <div>
      <h3>App</h3>
      <p>{count}</p>
      <button
        onClick={() => {
          dispatch1()
        }}
      >
        点我+2
      </button>
    </div>
  )
}

const mapStateToProps = (state, ownProps) => {
  const { count } = state
  return {
    count,
  }
}
const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    dispatch1: () => {
      dispatch(add(2))
    },
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

要点

  1. react-redux只是简化了在react项目中使用redux的过程
  2. redux和react-redux两个包都需要安装和使用,各司其职
  3. 需要知道Provider和connect的作用
  4. connect是高阶组件 => 把redux里面数据和修改数据的方法映射到组件中为了使用方便

react-redux结合hooks用法-useSelector

目标:结合hooks使用react-redux

内容

  1. react-redux提供了useSelector
  2. useSelector: 从Redux 的 store 中获取 状态(state) 数据。
  3. selector 函数应该是个纯函数

App.js

// import { add, addAfterOneSecond } from './store/actions'
import { useSelector } from 'react-redux'

const App = () => {
  const count = useSelector((state) => state.count)
  return (
    <div>
      <h3>App</h3>
      <p>{count}</p>
      <button
        onClick={() => {
          // dispatch(add(2))
        }}
      >
        点我+2
      </button>
      <button
        onClick={() => {
          // dispatch(addAfterOneSecond(2))
        }}
      >
        点我1s后+2
      </button>
    </div>
  )
}

export default App

要点

  • Provider组件依然需要使用

react-redux结合hooks用法-useDispatch

目标:结合hooks使用react-redux,修改数据

内容

  1. react-redux提供了useDispatch
  2. useDispatch:修改数据的hooks

App.js

import { add, addAfterOneSecond } from './store/actions'
import { useSelector, useDispatch } from 'react-redux'

const App = () => {
  const count = useSelector((state) => state.count)
  const dispatch = useDispatch()
  return (
    <div>
      <h3>App</h3>
      <p>{count}</p>
      <button
        onClick={() => {
          dispatch(add(2))
        }}
      >
        点我+2
      </button>
      <button
        onClick={() => {
          dispatch(addAfterOneSecond(2))
        }}
      >
        点我1s后+2
      </button>
    </div>
  )
}

export default App

要点:无

redux-异步action中间件redux-thunk的使用

目标:如何处理异步的action呢?比如点击按钮,1s后+1

内容

  1. redux-thunk的介绍,安装
  2. 配置redux-thunk
  3. 编写异步action
  4. App.js中测试

核心代码

store/reducers.js 不变

index.js不变

store/store.js

import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
import { addReducer } from './reducers.js'

// let store = createStore(addReducer)
const store = createStore(addReducer, applyMiddleware(thunk))
export default store


store/actions.js

export const add = (count) => {
  return {
    type: 'ADD',
    count,
  }
}

export const addAfterOneSecond = (count) => {
  return (dispatch) => {
    // console.log(dispatch)
    setTimeout(() => {
      dispatch(add(count))
    }, 1000)
  }
}

App.js

import { add, addAfterOneSecond } from './store/actions'
// import { add } from './store/actions'

const App = (props) => {
  const {
    store: { getState, dispatch },
  } = props
  const { count } = getState()
  return (
    <div>
      <h3>App</h3>
      <p>{count}</p>
      <button
        onClick={() => {
          dispatch(add(2))
        }}
      >
        点我+2
      </button>
      <button
        onClick={() => {
          dispatch(addAfterOneSecond(2))
        }}
      >
        点我1s后+2
      </button>
    </div>
  )
}

export default App

注意

  1. redux-thunk是专门处理redux中异步action的中间件
  2. 当要异步操作数据变化时,需要用redux-thunk包
  3. 常见的异步:定时器,ajax,注册事件

redux-devtools-extension的使用

目标:模拟vue的devtools,开发react项目时,通过chrome开发者工具调试跟踪redux状态

步骤

  1. 通过包管理器在项目中安装 yarn add redux-devtools-extension
  2. 在index.js中进行配置和导入
  3. 安装chrome浏览器插件
  4. 启动react项目,打开chrome开发者工具,测试

文档 redux-devtools-exension

小结

  1. react的作用
  2. redux的作用
  3. react-redux的作用
  4. redux-thunk的作用
  5. redux-thunk中useSelector作用
  6. redux-thunk中useDispatch作用

在这里插入图片描述
)]

小扩展:json-server模拟接口

1.全局安装: yarn global add json-server

2.运行: json-server db.json --port 8888

在这里插入图片描述

综合案例

模拟项目中的用法

  1. 页面组件中通过redux-thunk提供的hooks(useSelector) => 获取异步数据
  2. 页面组件redux-thunk提供的hooks(useDispatch)调用action
  3. store/action => 异步action(dispatch) => 内部axios => res 给到同步action
  4. store/action 同步action => 给到store

涉及新知识点

  1. reducer合并
  2. action传值应用
  3. 纯函数的解释(修改state的技巧)
    edux-devtools-extension的使用

目标:模拟vue的devtools,开发react项目时,通过chrome开发者工具调试跟踪redux状态

步骤

  1. 通过包管理器在项目中安装 yarn add redux-devtools-extension
  2. 在index.js中进行配置和导入
  3. 安装chrome浏览器插件
  4. 启动react项目,打开chrome开发者工具,测试

文档 redux-devtools-exension

小结

  1. react的作用
  2. redux的作用
  3. react-redux的作用
  4. redux-thunk的作用
  5. redux-thunk中useSelector作用
  6. redux-thunk中useDispatch作用

综合案例

模拟项目中的用法

  1. 页面组件中通过redux-thunk提供的hooks(useSelector) => 获取异步数据
  2. 页面组件redux-thunk提供的hooks(useDispatch)调用action
  3. store/action => 异步action(dispatch) => 内部axios => res 给到同步action
  4. store/action 同步action => 给到store

涉及新知识点

  1. reducer合并
  2. action传值应用
  3. 纯函数的解释(修改state的技巧)

http://www.niftyadmin.cn/n/1397212.html

相关文章

01-TypeScript 介绍-TypeScript常用类型

TypeScript TypeScript 介绍TypeScript 初体验TypeScript 常用类型TypeScript 高级类型TypeScript 类型声明文件在 React 中使用 TypeScript TypeScript 介绍 TS 官方文档TS 中文参考 - 不再维护 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q…

vue2快速生成代码片段

vue2快速生成代码片段 {// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible varia…

ts文件引入外部资源报错问题

ts中import图片 webpacktypescript项目中如下引入图片会报错(提示找不到该模块)&#xff1a; import xxx from "/imgs/KingLeague/appointment-btn.png"; import xxx from "/imgs/KingLeague/game-info.png";解决&#xff1a;添加图片模块声明文件 如下…

格式化千分位

格式化千分位 numFormat(value) {return Number(value).toLocaleString();// 原生js// let len value.length;// if (len < 3) {// return value;// }// let r len % 3;// value // r > 0// ? value.slice(0, r) // , // value// .slice…

JavaSE基础1

Java开发环境的准备&#xff1a;JDK简介、安装、常用命令 Java入门程序-HelloWorld HelloWorld程序常见问题 补充知识&#xff1a;Java程序的执行原理 补充知识&#xff1a;JDK的组成、跨平台原理 补充知识&#xff1a;JDK安装后Path和Java_home环境变量 Java背景知识 Java是美…

day03-java基础-运算符

java基础-运算符 1.运算符和表达式 运算符&#xff1a; ​ 就是对常量或者变量进行操作的符号。 ​ 比如&#xff1a; - * / 表达式&#xff1a; ​ 用运算符把常量或者变量连接起来的&#xff0c;符合Java语法的式子就是表达式。 ​ 比如&#xff1a;a b 这个整体就是…

day04-流程控制语句

第一章 流程控制语句 在一个程序执行的过程中&#xff0c;各条语句的执行顺序对程序的结果是有直接影响的。所以&#xff0c;我们必须清楚每条语句的执行流程。而且&#xff0c;很多时候要通过控制语句的执行顺序来实现我们想要的功能。 1.1 流程控制语句分类 ​ 顺序结构 …

05-java数组

数组概念 数组的定义 数组的静态初始化 地址值 数组元素访问 数组索引 数组遍历&#xff0c; 数组动态初始化 数组的两种初始化方式的区别 数组常见问题 数组练习 1.数组 概念&#xff1a; ​ 指的是一种容器&#xff0c;可以同来存储同种数据类型的多个值。 ​ 但是数组容器…