[react] Redux基本介绍 ===
redux 是什么?Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。当遇到如下问题时,建议开始使用 Redux:你有很多数据随时间而变化你希望状态有一个唯一确定的来源你发现将所有状态放在顶层组件中管理已不可维护redux 和 react 的关系Redux并不只为react应用提供状态管理, 它还支持其它的框架。为什么Rect要用 ReduxReact 是 DOM 的一个
目录
redux 是什么?
Redux 是 JavaScript 应用的状态容器,提供可预测的状态管理。
当遇到如下问题时,建议开始使用 Redux:
-
你有很多数据随时间而变化
-
你希望状态有一个唯一确定的来源
-
你发现将所有状态放在顶层组件中管理已不可维护
redux 和 react 的关系
Redux并不只为react应用提供状态管理, 它还支持其它的框架。
为什么Rect要用 Redux
React 是 DOM 的一个抽象层(UI 库),并不是 Web 应用的完整解决方案。因此react在涉及到数据的处理以及组件之间的通信时会比较复杂。
对于大型的复杂应用来说,这两方面恰恰是最关键的。因此,只用 React,写大型应用比较吃力。
-
2014 年 Facebook 提出了 Flux 架构的概念,引发了很多的实现。
-
2015 年,Redux 出现,将 Flux 与函数式编程(reducer)结合一起,很短时间内就成为了最热门的前端架构。
-
Flux 是最早的状态管理 工具,它提供了状态管理的思想,也提供对应的实现
-
除了 Flux、Redux 之外,还有:Mobx 等状态管理工具
-
主要的区别:组件之间的通讯问题
-
不使用 Redux (图左边) :
-
只能使用父子组件通讯、状态提升等 React 自带机制
-
处理远房亲戚(非父子)关系的组件通讯时乏力
-
组件之间的数据流混乱,出现 Bug 时难定位
-
-
使用 Redux (图右边):
-
集中式存储和管理应用的状态
-
处理组件通讯问题时,无视组件之间的层级关系
-
简化大型复杂应用中组件之间的通讯问题
-
数据流清晰,易于定位 Bug
-
react 多组件共享 - 案例
问题描述
多组件(跨层级的)共享数据
目录结构
├── src
├── store # redux目录,一般约定叫store
│ ├── index.js # 定义并导出store. 其中会导入reducer
│ └── reducer # reducer函数
├── App.js # 根组件,引入Father 和 Uncle组件
├── Father.js # Father组件。其中引入了Son组件
├── index.js # 项目的入口文件,会导入并渲染App.js
├── Son.js # Son组件
└── Uncle.js # Unclde组件
使用redux来解决的思路
-
redux可以无视组件层级
-
对于组件系统来说,redux就是一个第三方的,全局的变量
Redux 三个核心概念
图示
理解三个核心概念
核心概念:store
、action
、reducer
action
-
动作。
-
一个js对象,包含两个属性:
-
type: 标识属性,值是字符串。多个type用action分开
-
payload:数据属性,可选。表示本次动作携带的数据
-
-
actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
-
特点:
-
只描述做什么
-
JS 对象,必须带有
type
属性,用于区分动作的类型 -
根据功能的不同,可以携带额外的数据,配合该数据来完成相应功能
-
示例:
{ type: 'increment' }
{ type: 'decrement', count: 2 }
{ type: 'addTodo', name: '吃饭' }
{ type: 'removeTodo', id: 3 }
{ type: 'addN', payload: n }
{ type: 'addN', payload: {count:2} }
{ type: 'addN', payload: {name:'吃饭',age:18} }
reducer
-
一个函数
-
作用
-
-
初始化状态
-
修改状态
-
-
-
修改状态
根据传入的旧状态和action,返回新状态
公式:
(previousState, action) => newState
示例
const reducer = (state = 0, action) => {
switch (action.type) {
case 'add':
// 返回新的state
return state + 1
case 'addN':
// 返回新的state
return state + action.payload
default:
return state
}
}
store
-
store:仓库,Redux 的核心,整合 action 和 reducer
-
特点:
-
一个应用只有一个 store
-
维护应用的状态,获取状态:
store.getState()
-
创建 store 时接收 reducer 作为参数:
const store = createStore(reducer)
-
发起状态更新时,需要分发 action:
store.dispatch(action)
-
-
其他 API, — 订阅(监听)状态变化:
const unSubscribe = store.subscribe(() => {})
— 取消订阅状态变化:unSubscribe()
Redux功能演示核心代码
定义reuder
initState = 0
function reducer(state = initState, action) {
return state
}
定义action
const action1 = { type:'addN', payload: 12 }
// store.dispatch(action1)
const action2 = { type:'add', payload: 1 }
定义store
import { createStore } from 'redux'
// 创建 store
const store = createStore(reducer)
store 相关API
-
store获取状态
store.getState()
-
store修改数据,通过派发action。
store.dispatch({type:xxx, payload: xx}})
-
store添加订阅者。
// 格式:
// 取消订阅 = store.subscribe(订阅者)
// 订阅者:就是一个函数,当state值变化时,store会执行它
// store.subscript()的返回值也是一个函数,执行它时,它的
const unSubscribe = store.subscribe(() => {
// 状态改变时,执行相应操作
})
// 取消监听状态变化
4. 取消订阅者。unSubscribe()
核心代码
import { createStore } from 'redux'
initState = 0
function reducer(state = initState, action) {
return state
}
// 创建 store
const store = createStore(reducer)
// store获取状态
console.log(store.getState())
// 更新状态
// 1. dispatch 派遣,派出。表示:分发一个 action,也就是发起状态更新
// 2. store.dispatch会 调用reducer函数,并将action传递给reducer
const action1 = { type:'addN', payload: 12 }
store.dispatch(action1)
const action2 = { type:'add', payload: 1 }
store.dispatch(action2)
// store 添加订阅者
// store.subscribe
// 订阅者:就是一个函数,当state值变化时,store会执行它
const unSubscribe = store.subscribe(() => {
// 状态改变时,执行相应操作
console.log('数据变化了....')
})
// 取消监听状态变化
unSubscribe()
Redux 代码执行过程
获取默认值
只要创建 store,那么,Redux 就会调用一次 reducer, 且type是一个随机值。如下是一个示例:
这一次调用 reducer 的目的:获取状态的默认值。这个初始值将成为下一次调用 store.getState()
方法来获取 Redux 状态值的preState
-
type是随机值确保了它不会被用户业务逻辑处理,而只能去匹配默认值。
更新状态
-
当你需要更新状态时,就先分发动作
store.dispatch(action)
-
Redux 内部,store 就会调用 reducer,传入:上一次的状态(当前示例中就是:
0
)和 action({ type: 'add' }
),计算出新的状态,并返回 -
reducer 执行完毕后,将最新的状态交给 store,store 用最新的状态替换旧状态,状态更新完毕
import { createStore } from 'redux'
const store = createStore(reducer)
function reducer(state = 0, action) {
console.log('reducer:', state, action)
switch (action.type) {
case 'add':
return state + 1
default:
return state
}
}
console.log('状态值为:', store.getState()) // 10
// 发起更新状态:
// 参数: action 对象
store.dispatch({ type: 'increment' })
// 相当于: reducer(10, { type: 'increment' })
console.log('更新后:', store.getState()) // 11
解决问题-redux在react中使用
├── src
├── store # redux目录,一般约定叫store
│ ├── index.js # 定义并导出store. 其中会导入reducer
│ └── reducer # reducer函数
├── App.js # 根组件,引入Father 和 Uncle组件
├── Father.js # Father组件。其中引入了Son组件
├── index.js # 项目的入口文件,会导入并渲染App.js
├── Son.js # Son组件
└── Uncle.js # Unclde组件
store/index.js
用reducer来初始化store
import { createStore } from 'redux'
import reducer from './reducer'
export default createStore(reducer)
reducer.js
设置初始值,并提供修改数据的逻辑
const initState = 0
export default function reducer (state = initState, action) {
console.log(action)
switch (action.type) {
case 'addN':
return state + action.payload
case 'sub':
return state - 1
default:
return state
}
}
src/index.js
import React from 'react'
import ReactDom from 'react-dom'
import App from './App'
import store from './store/index.js'
ReactDom.render(<App />, document.getElementById('root'))
// 数据变化时,重新渲染
store.subscribe(() => {
ReactDom.render(<App />, document.getElementById('root'))
})
src/App.js
import React from 'react'
import Father from './Father'
import Uncle from './Uncle'
export default function App () {
return (
<div style={{ border: '1px solid #ccc', margin: 10, padding: 10 }}>
根组件
<Father />
<Uncle />
</div>
)
}
son.js
获取数据: store.getState()
修改数据: store.dispatch(action)
import React, { useState } from 'react'
import store from './store/index'
export default function Son () {
const [n, setN] = useState(12)
const add = () => {
store.dispatch({ type: 'addN', payload: n })
}
return (
<div style={{ border: '1px solid #ccc', margin: 10, padding: 10 }}>
子组件
{store.getState()}
<button onClick={add}>+n</button>
<input value={n} onChange={(e) => setN(e.target.value)} />
</div>
)
}
uncle.js
修改数据: store.dispatch(action)
import React from 'react'
import store from './store/index'
export default function Uncle () {
return (
<div style={{ border: '1px solid #ccc', margin: 10, padding: 10 }}>
Uncle组件
<button
onClick={() => {
store.dispatch({ type: 'sub' })
}}>
-1
</button>
</div>
)
}
更多推荐
所有评论(0)