Redux相关知识(什么是redux、redux的工作原理、redux的核心概念、redux的基本使用)(十一)

系列文章目录

第一章:React基础知识(React基本使用、JSX语法、React模块化与组件化)(一)
第二章:React基础知识(组件实例三大核心属性state、props、refs)(二)
第三章:React基础知识(事件处理、受控组件与非受控组件、高阶函数、组件的生命周期)(三)
第四章:React脚手架应用(创建脚手架、代理配置、ajax相关、组件通信)(四)
第五章:react-router5路由相关一(路由相关概念、基本使用、NavLink与NavLink的封装、Switch的使用、严格匹配、路由重定向、路由组件与一般组件的区别)(五)
第六章:react-router5路由相关二(嵌套路由、路由传参、replace、编程式路由导航、withRouter的使用、BrowserRouter与HashRouter的区别)(六)
第七章:React-Router6路由相关一(路由的基本使用、重定向、NavLink·、路由表、嵌套路由)(七)
第八章:React-Router6路由相关二(路由传参、编程式路由导航、路由相关hooks)(八)
第九章:React相关扩展一(setState、lazyLoad、Hooks相关)(九)
第十章:React相关扩展二(Fragment、Content、组件优化、render props、错误边界)(十)
第十一章:Redux相关知识(什么是redux、redux的工作原理、redux的核心概念、redux的基本使用)(十一)
第十二章:React-Redux相关知识(什么是react-redux、react-redux的原理、react-redux相关API、react-redux的基本使用)(十二)



一、什么是Redux

1.1 概念

  • Redux 是 JavaScript应用的状态容器,提供可预测的状态管理。可以开发出行为稳定可预测的应用,运行于不同的环境(客户端、服务器、原生应用),并且易于测试。
  • Redux 是一个使用叫做“action”的事件来管理和更新应用状态的模式和工具库,它以集中式Store的方式对整个应用中使用的状态进行集中管理,其规则确保状态只能以可预测的方式更新。
  • Redux提供的模式和工具使您更容易理解应用程序中的状态何时、何地、为什么以及如何更新,以及当这些更改发生时您的应用程序逻辑将如何表现。
  • 类似于vuex 但是不同于vuex,可以对状态进行管理。

1.2 何时使用?

  • 在应用的大量地方,都存在大量的状态
  • 应用状态会随着时间的推移而频繁更新
  • 更新该状态的逻辑可能很复杂
  • 中型和大型代码量的应用,很多人协同开发
  • 不同身份的⽤户有不同的使⽤⽅式(⽐如普通⽤户和管理员)
  • 与服务器⼤量交互,或者使⽤了WebSocket
  • View要从多个来源获取数据
  • 某个组件的状态,需要共享某个状态需要在任何地⽅都可以拿到
  • ⼀个组件需要改变全局状态
  • ⼀个组件需要改变另⼀个组件的状态

1.3 redux的工作原理

在这里插入图片描述
在这里插入图片描述

  • 页面初始渲染时:

    • 使用最顶层的 root reducer 函数创建 Redux store
    • store 调用一次 root reducer,并将返回值保存为它的初始 state
    • 当 UI 首次渲染时,UI 组件访问 Redux store 的当前 state,并使用该数据来决定要呈现的内容。
    • 同时监听store 的更新,以便他们可以知道 state 是否已更改。
  • 页面更新渲染时:

    • dispatch 一个 actionRedux store,例如 dispatch({type:'counter/increment'})
    • store之前的 state当前的 action 再次运行 reducer 函数,并将返回值保存为新的 state
    • store 通知所有订阅过的 UI通知它们 store 发生更新
    • 每个订阅过 store 数据的 UI 组件都会检查它们需要的 state 部分是否被更新。
    • 发现数据被更新的每个组件都强制使用新数据重新渲染,紧接着更新网页

二、核心概念

应用的整体全局状态以对象树的方式存放于单个 store唯一改变状态树的方法创建 action,一个描述发生了什么的对象,并将其 dispatch 给 store。 要指定状态树如何响应 action 来进行更新,你可以编写纯 reducer 函数,这些函数根据旧 state 和 action 来计算新 state

2.1 state

  • 托管给redux管理的状态
  • 示例代码:
let state = { 
	todos:[], 
	params:{} 
}

2.2 action

  • Action

    • Action 描述当前发⽣的事情。改变State的唯⼀办法,就是使⽤Action。它会运送数据到 Store。
    • Action 本质上是 JavaScript 普通对象。action必须使⽤⼀个字符串类型的 type字段表示将要执⾏的动作
    • type 字段是一个字符串,给这个 action 一个描述性的名字,比如"todos/todoAdded"。
    • action对象可以有其他字段,其中包含有关发生的事情的附加信息。按照惯例,我们将该信息放在名为data的字段中,也可放放到其他属性中,不过最好放到data中。
    • 示例代码:
    { type: 'ADD_TODO', text: '去游泳馆' } 
    { type: 'TOGGLE_TODO', index: 1 } 
    { type: 'SET_VISIBILITY_FILTER', filter: 'completed' }
    
  • Action Creator

    • action creator 是一个创建并返回一个 action 对象的函数。它的作用是让你不必每次都手动编写 action对象

    • 示例代码:

    const addTodo = data => ({type: 'todos/todoAdded',data})
    

2.3 reducer(重要)

  • reducer一个函数接收当前的state和一个action 对象,必要时决定如何更新状态,并返回新状态。函数签名是:(state, action) => newState。可以将reducer 视为一个事件监听器,它根据接收到的action(事件)类型处理事件。

  • Reducer 必需符合以下规则:

    • 仅使用 state 和 action 参数计算新的状态值
    • 禁止直接修改 state。必须通过复制现有的 state 并对复制的值进行更改的方式来做不可变更新
    • 禁止任何异步逻辑、依赖随机值或导致其他“副作用”的代码
  • reducer 函数内部的逻辑通常遵循以下步骤:

    • 检查 reducer 是否联系这个 action
      • 如果是,则复制 state,使用新值更新 state 副本,然后返回新 state
      • 否则,返回原来的 state 不变
  • 示例代码:

    // 初始化状态
    const initialState = { value: 0, index: 1 }
    
    function counterReducer(preState=initialState, action) {
    		//从action对象中获取:type、data
    		const {type,data} = action
    		//根据type决定如何加工数据
    		switch (type) {
    			case 'increment': //如果是加
    				return { 
    					...preState
    					value:preState.value + data
    				}
    			case 'decrement': //若果是减
    				return { 
    					...preState
    					value:preState.value - data
    				}
    			default:
    				// 返回prestate 不变
    				return preState
    		}
    }
    

2.4 store

  • 当前 Redux 应用的状态存在于一个名为 store 的对象中。store 是通过传入一个reducer来创建的,并且有一个getState 的方法,它返回当前状态值

  • Store 就是保存数据的地⽅,可以把它看成⼀个容器。整个应⽤只能有⼀个Store。Redux提供createStore这个函数,⽤来⽣成Store

  • 示例代码:

    //引入createStore,专门用于创建redux中最为核心的store对象
    // 旧版本的引入
    // import {createStore} from 'redux'
    // 新版本的引入
    import { legacy_createStore as createStore } from 'redux'
    //引入为Count组件服务的reducer
    import reducer from './reducer'
    //暴露store
    export default createStore(reducer)
    /* 如果该仓库用多个reducer,则使用combineReducers函数来合并reducer,
       可以通过combineReducers组合多个Reducer,然后通过createStore来创建状态机。*/
    const store2=createStore(combineReducers({
    	 todos,
    	 counter, 
    }));
    

    或者直接使用@reduxjs/toolkit包中的configureStore方法来生成store

    import { configureStore } from '@reduxjs/toolkit'
    const store = configureStore({ reducer})
    

    仓库创建好了之后,将store引入到需要使用仓库的组件中。

    import store from './store/index.js'
    // 分发动作
    store.dispatch({type:'',data:''})
    // 获取仓库数据
    store.getState();
    

2.5 dispatch

  • Redux store 有一个方法叫 dispatch更新 state 的唯一方法调用 store.dispatch() 并传入一个action对象。store 将执行所有reducer函数并计算出更新后的state,调用 getState()
    可以获取新state。

  • 示例代码

    store.dispatch({ type: 'counter/increment' })
    console.log(store.getState())
    // {value: 1}
    
  • dispatch 一个 action 可以形象的理解为 "触发一个事件"。发生了一些事情,我们希望 store
    知道这件事。Reducer 就像事件监听器一样,当它们收到关注的 action 后,它就会更新 state 作为响应。 我们通常调用 action creator 来调用 action

  • 示例代码

    const increment = () => {
     return {
    	 type: 'counter/increment'
     	}
    }
    // 分发动作
    store.dispatch(increment())
    console.log(store.getState())
    

2.6 subscribe(listener)

  • 添加一个变化监听器。每当dispatch action 的时候就会执行,state
    树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。你可以在变化监听器里面进行
    dispatch(),如果需要解绑这个变化监听器,执行 subscribe 返回的函数即可。

  • 参数listener (Function):当 dispatch action 的时候都会执行的回调。state 树中的一部分可能已经变化。你可以在回调函数里调用 getState() 来拿到当前 state。

  • 返回值(Function): 一个可以解绑变化监听器的函数。

    // 监听方法一
    store.subscribe(() => {
     this.setState({
     ...store.getState()
     });
    }); //订阅者做的事情
    
    // 监听方法二
    store.subscribe(()=>{
    	ReactDOM.render(<App/>,document.getElementById('root'))
    })
    

三、redux的基本使用(搭建redux环境)

  • 安装

    npm install redux
    
  • 主要API

    • createStore(reducer, [preloadedState], [enhancer]) 创建仓库
    • combineReducers(reducers) 合并reducer
    • applyMiddleware(...middlewares) 应用中间件
  • store相关API

    • store.getState() 获取仓库中的状态
    • store.dispatch(action) 分发到某个动作
    • store.subscribe(listener) 订阅仓库内状态更新
    • replaceReducer(nextReducer) 替换reducer
  • 代码案例片段:
    index.js

    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './App'
    import store from './redux/store'
    
    ReactDOM.render(<App/>,document.getElementById('root'))
    
    store.subscribe(()=>{
    	ReactDOM.render(<App/>,document.getElementById('root'))
    })
    

    App.js

    import React, { Component } from 'react'
    import Count from './components/Count'
    
    export default class App extends Component {
    	render() {
    		return (
    			<div>
    				<Count/>
    			</div>
    		)
    	}
    }
    
    

    redux/count_action.js(该文件专门为Count组件生成action对象)

    //同步action,就是指action的值为Object类型的一般对象
    export const createIncrementAction = data => ({type:'increment',data})
    export const createDecrementAction = data => ({type:'decrement',data})
    
    //异步action,就是指action的值为函数,异步action中一般都会调用同步action,异步action不是必须要用的。
    export const createIncrementAsyncAction = (data,time) => {
    	return (dispatch)=>{
    		setTimeout(()=>{
    			dispatch(createIncrementAction(data))
    		},time)
    	}
    }
    

    redux/count_reducer.js

    /* 
    	1.该文件是用于创建一个为Count组件服务的reducer,reducer的本质就是一个函数
    	2.reducer函数会接到两个参数,分别为:之前的状态(preState),动作对象(action)
    */	
    const initState = {
    	value:0,index:1
    } 
    //初始化状态
    export default function countReducer (preState = initState, action) {
    	console.log('preState:',preState);
    	console.log('action:',action);
    
    	//从action对象中获取:type、data
    	const { type, data } = action
    	//根据type决定如何加工数据
    	switch (type) {
    		case 'increment': //如果是加
    			return {
    				...preState,
    				value: preState.value + data
    			}
    		case 'decrement': //若果是减
    			return {
    				...preState,
    				value: preState.value - data
    			}
    		default:
    			return preState
    	}
    }
    

    redux/store.js

    /* 
    	该文件专门用于暴露一个store对象,整个应用只有一个store对象
    */
    
    //引入createStore,专门用于创建redux中最为核心的store对象
    // 旧版
    // import { createStore } from 'redux'
    //新版
    import { legacy_createStore as createStore, applyMiddleware } from 'redux'
    //引入为Count组件服务的reducer
    import countReducer from './count_reducer'
    //引入redux-thunk,用于支持异步action
    import thunk from 'redux-thunk'
    //暴露store
    export default createStore(countReducer, applyMiddleware(thunk))
    

    components/Count.jsx

    	import React, { Component } from 'react'
    //引入store,用于获取redux中保存状态
    import store from '../../redux/store'
    //引入actionCreator,专门用于创建action对象
    import {
    	createIncrementAction,
    	createDecrementAction,
    	createIncrementAsyncAction
    } from '../../redux/count_action'
    
    export default class Count extends Component {
    
    	state = {carName:'奔驰c63'}
    
    	/* componentDidMount(){
    		//检测redux中状态的变化,只要变化,就调用render
    		store.subscribe(()=>{
    			this.setState({})
    		})
    	} */
    
    	//加法
    	increment = ()=>{
    		const {value} = this.selectNumber
    		store.dispatch(createIncrementAction(value*1))
    	}
    	//减法
    	decrement = ()=>{
    		const {value} = this.selectNumber
    		store.dispatch(createDecrementAction(value*1))
    	}
    	//奇数再加
    	incrementIfOdd = ()=>{
    		const {value} = this.selectNumber
    		const count = store.getState()
    		if(count % 2 !== 0){
    			store.dispatch(createIncrementAction(value*1))
    		}
    	}
    	//异步加
    	incrementAsync = ()=>{
    		const {value} = this.selectNumber
    		// setTimeout(()=>{
    			store.dispatch(createIncrementAsyncAction(value*1,500))
    		// },500)
    	}
    
    	render() {
    		return (
    			<div>
    				<h1>当前求和为:{store.getState()}</h1>
    				<select ref={c => this.selectNumber = c}>
    					<option value="1">1</option>
    					<option value="2">2</option>
    					<option value="3">3</option>
    				</select>&nbsp;
    				<button onClick={this.increment}>+</button>&nbsp;
    				<button onClick={this.decrement}>-</button>&nbsp;
    				<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>&nbsp;
    				<button onClick={this.incrementAsync}>异步加</button>&nbsp;
    			</div>
    		)
    	}
    }
    

    运行结果:
    在这里插入图片描述

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值