Redux
持续更新中…………
redux是独立的一个状态管理数据状态工具
应用中所有的state都以一个对象树的形式存在在一个单一的store中,唯一改变state的办法是触发action,一个描述发生什么的对象,为了描述action如何改变state,需要编写一个reduces
例如
function counter(state = 3, action){
switch (action.type) {
case "TODO_ADD": // 添加todo
return ++state
default:
return state
}
}
const store = createStore(counter)
在react中使用
import { createStore } from "react-redux"
function counter(state = 3, action){
switch (action.type) {
case "ADD": // 添加todo
return ++state
default:
return state
}
}
const store = createStore(counter)
render() // 初始化渲染
function render(){
ReactDom.render(
<div>
<p onClick={()=>{
store.dispatch({type:"ADD"})
}}>{counter}</p>
</div>,
document.getElementById("root")
)
}
// 当触发事件修改counter的值时候,页面并没有渲染,是因为没有感知到变化,使用subcribe可以监听变化,然后重新渲染
store.subcribe(()=>{
render()
})
核心概念
Redux中不能直接修改state,因为他没有setter(修改器方法)只能使用action修改,action是一个普通的js对象
强制使用action修改state的好处
1、可以清楚的知道state为什么改变,在哪儿改变。把action和state串起来开发一些函数,这就是reducer
redux的三大原则
1、单一数据源
整个应用的state被存储在一个object tree中,并且这个object tree只存在于唯一一个store中
2、state是只读的
唯一改变state的方法是触发action,action是一个用于描述发生事件的普通对象。 这样确保了视图和网络请求都不能直接修改state,相反它们只能表达出想要修改的意图。因为state都是集中化处理,并且严格按照一个接一个的顺序执行,因此不用担心异步
3、使用纯函数修改
为了描述action如何改变state tree,需要编写reducers Reducer只是一些纯函数,接收先前的state和actin,并且返回新的state。一开始可以只用一个reducer。但随着项目的扩大,可以拆分成多个小的reducer,分别独立操作state tree 不同部分,可控制调用顺序
const todos = (state = [], action) => {
switch (action.type) {
case 'ADD_TODO':
return [
...state,
{
id: action.id,
text: action.text,
completed: false
}
]
case 'TOGGLE_TODO':
return state.map(todo =>
(todo.id === action.id) ?
{
...todo,
completed: !todo.completed
} :
todo
)
default:
return state
}
}
export default todos
const visibilityFilter = (state = 'SHOW_ALL', action) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter
default:
return state
}
}
export default visibilityFilter
// store/index.js
import {
combineReducers
} from 'redux'
import todos from './todos'
import visibilityFilter from './visibilityFilter'
export default combineReducers({
todos,
visibilityFilter
})
// index.js
import { createStore } from "redux";
import todoApp from "./reducers";
import App from "./App";
let store = createStore(todoApp);
拆分Reducer之后使用combineReducers合并小的reducer
Action
Action是把数聚从应用传到store的有效载荷,是数聚store的唯一来源,可以通过store.dispatch()将action传到store
action对象中除type外,其他结构由自己决定,一般会传state数聚中的数据id,进行方便查找
例如:{type:"ADD",index:5}
Reducer
只是一个接受state和action并返回一个新的state函数
reducer指定了应用中状态的变化如何响应actions并发送到store中,记住actions只是描述了有事情发生了这一事实,没有描述应用如何更新state
要一直保持reducer纯净,永远不要在reducer里做一下操作
1、修改传入的参数
2、执行又副作用的操作,如API和路由跳转
3、调用非纯函数 如Math.random()
注意点:
1、 在返回新的state的时候使用Object.assign()会修改第一个参数的值,所以第一个参数要设置{} object.assign({},state)
2、在type是位置的情况下,一定要返回旧的state
store的职责
1、维持应用的state
2、提供getState()方法获取state
3、提供dispatch({})更新state
4、通过subcribe(()=>{}) 注册监听器
5、通过subcribe(()=>{}) 返回的方法取消监听
store只能有一个,需要拆分逻辑时,应该使用reducer组合,而不是创建多个store
在reducer中讲到使用combineReducers()将多个reduce合并成为一个,然后使用createStore()创建一个store
let store = createStore(todoApp); // 导入合并之后的reducers
数据流
严格的单向数据流是Redux的设计核心,单向数据流可使得数据改变都是可预测的
Redux应用中的数据的生命周期遵循4个步骤
1、调用srore.dispatch(action)
action就是一个描述发生了什么的普通对象 ,可以在任何地方调用store.dispatch(action)
2、Redux store会调用传入的reducer函数
reducer是纯函数,仅仅用于计算下一个state,完全是可预测的:多次传入相同的输入,必须产生相同的输出
3、根reducer应该吧多个子reducer输出合并成一个单一的state树,使用combireReducer()合并
4、Redux store保存了根reducer返回的完成的state树
新的树就是下一个应用state,在所有订阅store.subscribe()的监听器都将被调用,监听器里可以调用store.getState()获得当前state
搭配React
使用 npm install react-redux -S 下载
传入store的方法
所有容器组件都可以访问Redux store,所以可以手动监听,一种方式是把它以props的形式传入到所有容器组件中,但这太麻烦,因为要使用store把组件包一层,仅仅因为恰好在组件数中渲染了一个容器组件
建议使用方式:使用指定的react redux组件,让所有容器组件都可以访问store,而不用显示传递,只需要渲染根组件就可以
render(
<Provider store={store}>
{/* <App /> */} <App> </App>
</Provider>,
document.getElementById("root")
);
在组件中获取store中state的值
1、使用高阶组件connect()传递参数返回新组件
export default connect(state=>({todos:state.todos}))(Todo) // 组件
2、有了hooks之后就可以使用hooks获取
hooksAPI
1、 传递store
2、useDispatch 获取dispatch方法
3、useStore获取store
4、useSelector 获取state
5、connect() 高阶函数:传入数据返回一个新的函数,然后再传入组件返回一个新的组件
后续会更新异步调用…………