Redux学习(一)——Redux的使用过程

一、为什么需要redux

  • JavaScript开发的应用程序,已经变得越来越复杂了:
  1. JavaScript需要管理的状态越来越多,越来越复杂;
  2. 这些状态包括服务器返回的数据、缓存数据、用户操作产生的数据等等,也包括一些UI的状态,比如某些元素是否被选中,
    是否显示加载动效,当前分页;
  • 管理不断变化的state是非常困难的:
  1. 状态之间相互会存在依赖,一个状态的变化会引起另一个状态的变化,View页面也有可能会引起状态的变化;
  2. 当应用程序复杂时,state在什么时候,因为什么原因而发生了变化,发生了怎么样的变化,会变得非常难以控制和追踪;
  • React是在视图层帮助我们解决了DOM的渲染过程,但是State依然是留给我们自己来管理:
  1. 无论是组件定义自己的state,还是组件之间的通信通过props进行传递;也包括通过Context进行数据之间的共享;
  2. React主要负责帮助我们管理视图,state如何维护最终还是我们自己来决定;
    在这里插入图片描述
  • Redux就是一个帮助我们管理State的容器:Redux是JavaScript的状态容器,提供了可预测的状态管理;

  • Redux除了和React一起使用之外,它也可以和其他界面库一起来使用(比如Vue),并且它非常小(包括依赖在内,只有2kb)

二、Redux的核心理念 - Store

Redux的核心理念非常简单。

  • 比如我们有一个朋友列表需要管理:
  1. 如果我们没有定义统一的规范来操作这段数据,那么整个数据的变化就是无法跟踪的;
  2. 比如页面的某处通过products.push的方式增加了一条数据;
  3. 比如另一个页面通过products[0].age = 25修改了一条数据;

整个应用程序错综复杂,当出现bug时,很难跟踪到底哪里发生的变化;
在这里插入图片描述

三、Redux的核心理念 - action

Redux要求我们通过action来更新数据:

  • 所有数据的变化,必须通过派发(dispatch)action来更新;
  • action是一个普通的JavaScript对象,用来描述这次更新的type和content;

比如下面就是几个更新friends的action:

  • 强制使用action的好处是可以清晰的知道数据到底发生了什么样的变化,所有的数据变化都是可跟追、可预测的;
  • 当然,目前我们的action是固定的对象,真实应用中,我们会通过函数来定义,返回一个action;

在这里插入图片描述

四、Redux的核心理念 - reducer

但是如何将state和action联系在一起呢?答案就是reducer

  • reducer是一个纯函数;
  • reducer做的事情就是将传入的state和action结合起来生成一个新的state;

在这里插入图片描述

五、Redux的三大原则

  1. 单一数据源
  • 整个应用程序的state被存储在一颗object tree中,并且这个object tree只存储在一个 store 中:
  • Redux并没有强制让我们不能创建多个Store,但是那样做并不利于数据的维护; p 单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改;
  1. State是只读的
  • 唯一修改State的方法一定是触发action,不要试图在其他地方通过任何的方式来修改State:
  • 这样就确保了View或网络请求都不能直接修改state,它们只能通过action来描述自己想要如何修改state;
  • 这样可以保证所有的修改都被集中化处理,并且按照严格的顺序来执行,所以不需要担心race condition(竟态)的问题;
  1. 使用纯函数来执行修改
  • 通过reducer将 旧state和 actions联系在一起,并且返回一个新的State:
  • 随着应用程序的复杂度增加,我们可以将reducer拆分成多个小的reducers,分别操作不同state tree的一部分;
  • 但是所有的reducer都应该是纯函数,不能产生任何的副作用;

六、Redux的使用过程

  1. 创建一个对象,作为我们要保存的状态:
  2. 创建Store来存储这个state
  • 创建store时必须创建reducer;
  • 我们可以通过 store.getState 来获取当前的state
  1. 通过action来修改state
  • 通过dispatch来派发action;
  • 通常action中都会有type属性,也可以携带其他的数据;
  1. 修改reducer中的处理代码
  • 这里一定要记住,reducer是一个纯函数,不需要直接修改state; - 后面我会讲到直接修改state带来的问题;
  1. 可以在派发action之前,监听store的变化:
    在这里插入图片描述
const redux = require('redux')
const initalState = {counter: 0
}
// reducer
function reducer(state = initalState, action) {switch (action.type) {case 'INCREMENT':return {...state, counter: state.counter + 1}case 'DECREMENT':return {...state, counter: state.counter - 1}case 'ADD_NUMBER':return {...state, counter: state.counter + action.num}case 'SUB_NUMBER':return {...state, counter: state.counter - action.num}default:return state}
}// store
const store = redux.createStore(reducer)// 订阅store的修改
store.subscribe(() => {console.log('counter: ', store.getState().counter)
})// action
const action1 = {type: 'INCREMENT'}
const action2 = {type: 'DECREMENT'}
const action3 = {type: 'ADD_NUMBER', num: 5}
const action4 = {type: 'SUB_NUMBER', num: 12}// 派发action
store.dispatch(action1)
store.dispatch(action2)
store.dispatch(action3)
store.dispatch(action4)

七、Redux结构划分

如果我们将所有的逻辑代码写到一起,那么当redux变得复杂时代码就难以维护。

接下来,我会对代码进行拆分,将store、reducer、action、constants拆分成一个个文件。

  1. 创建store/index.js文件:
  2. 创建store/reducer.js文件:
  3. 创建store/actionCreators.js文件:
  4. 创建store/constants.js文件:

在这里插入图片描述

注意:node中对ES6模块化的支持
在这里插入图片描述

  • 目前我使用的node版本是v14.16.1,从node v13.2.0开始,node才对ES6模块化提供了支持:
  • node v13.2.0之前,需要进行如下操作:
  1. 在package.json中添加属性: “type”: “module”;

  2. 在执行命令中添加如下选项:node --experimental-modules src/index.js;

  3. node v13.2.0之后,只需要进行如下操作:
    在package.json中添加属性: “type”: “module”;
    注意:导入文件时,需要跟上.js后缀名;

index.js:
在这里插入图片描述
store/index.js:
在这里插入图片描述
store/actionCreator.js:
在这里插入图片描述
store/reducer.js:
在这里插入图片描述
store/constants.js:
在这里插入图片描述
在这里插入图片描述

八、Redux官方图

在这里插入图片描述

九、redux融入react代码

目前redux在react中使用是最多的,所以我们需要将之前编写的redux代码,融入到react当中去。
这里我创建了两个组件:

  1. Home组件:其中会展示当前的counter值,并且有一个+1和+5的按钮;
  2. About组件:其中会展示当前的counter值,并且有一个-1和-5的按钮;

在这里插入图片描述
核心代码主要是两个:
3. 在 componentDidMount 中定义数据的变化,当数据发生变化时重新设置 counter;
4. 在发生点击事件时,调用store的dispatch来派发对应的action;
在这里插入图片描述

Home.js:

import React, {PureComponent} from 'react';
import store from "../store";import {addAction} from "../store/actionCreator";class Home extends PureComponent {constructor(props) {super(props);this.state = {counter: store.getState().counter}}componentDidMount() {this.unsubscribue = store.subscribe(() => {this.setState({counter: store.getState().counter})})}componentWillUnmount() {this.unsubscribue()}render() {return (<div><h1>Home</h1><h3>当前计数:{this.state.counter}</h3><button onClick={e => this.increment()}>+1</button><button onClick={e => this.addNumber(5)}>+5</button></div>);}increment () {store.dispatch(addAction(1))}addNumber (num) {store.dispatch(addAction(num))}
}export default Home;

About.js:

import React, {PureComponent} from 'react';
import store from "../store";
import {addAction, subAction} from "../store/actionCreator";class About extends PureComponent {constructor(props) {super(props);this.state = {counter: store.getState().counter}}componentDidMount() {this.unsubscribue = store.subscribe(() => {this.setState({counter: store.getState().counter})})}componentWillUnmount() {this.unsubscribue()}render() {return (<div><h1>About</h1><h3>当前计数:{this.state.counter}</h3><button onClick={e => this.subNumber(1)}>-1</button><button onClick={e => this.subNumber(5)}>-5</button></div>);}subNumber (num) {store.dispatch(subAction(num))}
}export default About;

App.js:

import React, {PureComponent} from 'react';
import Home from "./pages/Home";
import About from "./pages/About";class App extends PureComponent {render() {return (<div><Home/><hr/><About/></div>);}
}export default App;

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/470252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redux学习(二)——封装connect函数

一、自定义connect函数 connect.js: import {PureComponent} from "react"; import store from "../store"; export function connect(mapStateToProps, mapDispatchToProps) {return function enhanceHOC(WrappedComponent) {return class extends PureC…

Redux学习(三)——redux-saga的使用、编写中间件函数、Reducer文件拆分

一、redux-devtools 我们之前讲过&#xff0c;redux可以方便的让我们对状态进行跟踪和调试&#xff0c;那么如何做到呢&#xff1f; redux官网为我们提供了redux-devtools的工具&#xff1b;利用这个工具&#xff0c;我们可以知道每次状态是如何被修改的&#xff0c;修改前后…

react-router的使用(一)——URL的hash、HTML5的history、Router的基本使用

一、阶段一&#xff1a;后端路由阶段 早期的网站开发整个HTML页面是由服务器来渲染的. 服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示. 但是, 一个网站, 这么多页面服务器如何处理呢? 一个页面有自己对应的网址, 也就是URL.URL会发送到服务器, 服务器会通过正…

react-router的使用(二)——NavLink的使用、Switch的作用、Redirect

一、NavLink的使用 需求&#xff1a;路径选中时&#xff0c;对应的a元素变为红色 这个时候&#xff0c;我们要使用NavLink组件来替代Link组件&#xff1a; activeStyle&#xff1a;活跃时&#xff08;匹配时&#xff09;的样式&#xff1b;activeClassName&#xff1a;活跃时…

群晖ffmpeg_群晖Video station支持DTS和EAC3

群晖video station这个套件现在经过群晖的打磨&#xff0c;现在还是不错的&#xff0c;支持硬件解码和蓝光等多媒体播放&#xff0c;比起PLEX和EMBY动辄好几百的会员费&#xff0c;这个免费的用起来还真香&#xff0c;但是因为种种小问题需要解决了&#xff0c;才能好用&#x…

react-router的使用(三)——路由的嵌套

一、路由的嵌套 在开发中&#xff0c;路由之间是存在嵌套关系的。 这里我们假设about页面中有三个页面内容&#xff1a; 企业历史、企业文化和联系我们&#xff1b;点击不同的链接可以跳转到不同的地方&#xff0c;显示不同的内容&#xff1b; 二、手动路由跳转 目前我们实现…

如何阅读一本书 pdf_《如何阅读一本书》:一本书,四个层次,看阅读小白如何逆袭?...

“读书不是为了雄辩和驳斥&#xff0c;也不是为了轻信和盲从&#xff0c;而是为了思考和权衡。”这是培根的一句名言&#xff0c;我们都曾经被这样的读书警句激励的斗志昂扬&#xff0c;于是立下目标一年或是一个月要读多少本书&#xff0c;结果发现一切是徒劳。你是否曾经斗志…

React Hooks的使用(一)——useState、useEffect解析

一、为什么需要Hook? Hook 是 React 16.8 的新增特性&#xff0c;它可以让我们在不编写class的情况下使用state以及其他的React特性&#xff08;比如生命周期&#xff09;。 我们先来思考一下class组件相对于函数式组件有什么优势&#xff1f;比较常见的是下面的优势&#xf…

React Hooks的使用(二)——useContext、useReducer、useCallback、useMemo解析

一、useContext的使用 在之前的开发中&#xff0c;我们要在组件中使用共享的Context有两种方式&#xff1a; 第一种方式&#xff1a;类组件可以通过 类名.contextType MyContext方式&#xff0c;在类中获取context&#xff1b; 第二种方式&#xff1a;多个Context或者在函数…

凸多边形面积_C++计算任意多边形的面积

任意多边形的面积计算_拾忆楓灵的博客-CSDN博客​blog.csdn.net计算任意多边形的面积 - tenos - 博客园​www.cnblogs.com完美解决计算3D空间任意多边形面积_Studiouss的博客-CSDN博客​blog.csdn.net求多边形面积公式&#xff08;已知顶点坐标&#xff09;_扬帆起航-CSDN博客​…

React Hooks的使用(三)——useRef、useImperativeHandle、useLayoutEffect解析、自定义Hook

一、useRef useRef返回一个ref对象&#xff0c;返回的ref对象再组件的整个生命周期保持不变。 最常用的ref是两种用法&#xff1a; 用法一&#xff1a;引入DOM&#xff08;或者组件&#xff0c;但是需要是class组件&#xff09;元素&#xff1b; 案例一&#xff1a;引用DOM …

python子类分配

原问题是将左边样式变成右边样式&#xff1a; 即有父类和子类&#xff0c;父类包括多个子类&#xff0c;怎样将子类匹配到父类下面的问题 代码如下 1 #!/usr/bin/python3.42 # -*- coding: utf-8 -*-3 4 arr1 ["S01","S01","S01","S02&quo…

react 网易云音乐实战项目笔记

0、项目规范 一、路由相关 npm i react-router-dom npm i react-router-config // 用于配置路由映射的关系数组1. 路由重定向 访问 /路径 》 重定向到 /discover路径 2. 二级路由&#xff1a; 二、网络请求相关 npm i axios页面中使用暴露 出来的request发送网络请求&#…

react项目打包

一、react项目打包 对于使用脚手架创建的项目&#xff0c;打包是一件非常容易的事情&#xff1a; yarn build其他文件没有太多要解析的&#xff0c;我们看一下js文件&#xff1a; [hash].chunk.js 代表是所有依赖的第三方库&#xff0c; vendor(第三方库) 的代码&#xff1b…

React SSR

一、为什么需要SSR呢&#xff1f; 单页面富应用的局限&#xff1a; 之前我们开发的应用程序&#xff0c;如果直接请求可以看到上面几乎没有什么内容。 但是为什么我们页面可以看到大量的内容呢&#xff1f; 因为当我们请求下来静态资源之后会执行JS&#xff0c;JS会去请求数…

Vue3 组件通信学习笔记

一、父子组件之间通信 父子组件之间如何进行通信呢&#xff1f; 父组件传递给子组件&#xff1a;通过props属性&#xff1b;子组件传递给父组件&#xff1a;通过$emit触发事件&#xff1b; 1.1 父组件传递给子组件 在开发中很常见的就是父子组件之间通信&#xff0c;比如父…

Vue3 slot插槽——(默认插槽、具名插槽、作用域插槽)

一、认识插槽Slot 在开发中&#xff0c;我们会经常封装一个个可复用的组件&#xff1a; 前面我们会通过props传递给组件一些数据&#xff0c;让组件来进行展示&#xff1b;但是为了让这个组件具备更强的通用性&#xff0c;我们不能将组件中的内容限制为固定的div、span等等这…

Vue动态组件和组件缓存

一、切换组件案例 比如我们现在想要实现了一个功能&#xff1a; 点击一个tab-bar&#xff0c;切换不同的组件显示&#xff1b; 这个案例我们可以通过两种不同的实现思路来实现&#xff1a; 方式一&#xff1a;通过v-if来判断&#xff0c;显示不同的组件&#xff1b; 方式二…

Webpack的代码分包Vue3中定义异步组件分包refs的使用

一、默认的打包过程&#xff1a; 默认情况下&#xff0c;在构建整个组件树的过程中&#xff0c;因为组件和组件之间是通过模块化直接依赖的&#xff0c;那么webpack在打包时就会将组件模块打包到一起&#xff08;比如一个app.js文件中&#xff09;&#xff1b; 这个时候随着项…

组件的v-model Mixin extends

一、组件的v-model 前面我们在input中可以使用v-model来完成双向绑定&#xff1a; 这个时候往往会非常方便&#xff0c;因为v-model默认帮助我们完成了两件事&#xff1b;v-bind:value的数据绑定 和 input的事件监听&#xff1b; 如果我们现在封装了一个组件&#xff0c;其…