摘要:簡介是的狀態(tài)管理器,便于我們更加清晰管理追蹤應(yīng)用程序中變化莫測的狀態(tài)變更。
簡介Redux是JS的狀態(tài)管理器,便于我們更加清晰管理追蹤應(yīng)用程序中變化莫測的狀態(tài)變更。Redux采用 的方式對數(shù)據(jù)進(jìn)行管理,這種方式的好處在于只能從單一的方向進(jìn)行數(shù)據(jù)變更,剔除了數(shù)據(jù)能五花八門改變的方式,有利于我們對數(shù)據(jù)的變化的追蹤,同時(shí)降低項(xiàng)目后期的維護(hù)成本。
Redux狀態(tài)管理器的核心思想:
store狀態(tài)樹
action行為狀態(tài)對象
reducer行為狀態(tài)的處理
簡單的說就是首先使用定義狀態(tài)樹中所有需要發(fā)生變化的狀態(tài),然后使用定義對應(yīng)的行為的處理并將處理后的狀態(tài)返回,最后將各個(gè)處理后的狀態(tài)按照一定的規(guī)律組合成對象就形成了store狀態(tài)樹。
因此store狀態(tài)樹就是一個(gè)對象,定義了對象里某個(gè)遞歸字段對應(yīng)值需要發(fā)生變化時(shí)需要的信息,然后經(jīng)過處理,最終使?fàn)顟B(tài)樹中對應(yīng)的遞歸字段的值發(fā)生變化
文章中展示的實(shí)例demo有些并未能直接在界面上體現(xiàn),需要配合redux-tool工具觀看狀態(tài)樹的變化,瀏覽器中安裝相應(yīng)的redux調(diào)試工具方法
示例 redux-1:
//定義一個(gè)加法行為需要的參數(shù)
const addAction = (num1,num2) => {
return ({
type: "ADD",
num1,
num2,
})
}
//定義處理加法的行為邏輯
const addReducer = (state,action) => {
if(action.type === "ADD") {
return {
result: action.num1 + action.num2
}
}
}
//生成整個(gè)狀態(tài)樹
const store = createStore(addReducer,{})
//獲取整個(gè)狀態(tài)樹對象
store.getState() //undefined
//此時(shí)由于需要觸發(fā)某個(gè)行為
store.dispatch(addAction(1,2))
//獲取整個(gè)狀態(tài)樹對象
store.getState() //{result:3}
以上簡單的幾個(gè)操作就是Redux的整個(gè)實(shí)現(xiàn)思想
使用原則
對象中必須擁有字段,redux主要是根據(jù)該字段選擇對應(yīng)的進(jìn)行處理
處理函數(shù)必須 純函數(shù),接收相應(yīng)的state,經(jīng)過處理后返回新的state。不允許返回undefined或者null
當(dāng)需要觸發(fā)行為變更相關(guān)的狀態(tài)樹信息時(shí),必須調(diào)用dispatch方法觸發(fā)更新操作
決定狀態(tài)樹中內(nèi)容的是的返回值,并非行為對象,因此如果沒有對進(jìn)行處理,即便使用dispatch觸發(fā)更新,狀態(tài)樹也不會發(fā)生任何的變化
redux是同步進(jìn)行的,因此創(chuàng)建行為、觸發(fā)更新操作dispatch等方法都必須是同步操作,若需要支持異步操作時(shí),需要增加中間件的支持,比如 redux-promise、redux-thunk 等
API createStore創(chuàng)建狀態(tài)樹
@params reducer 處理行為的函數(shù)
@params preloadedState 初始化默認(rèn)狀態(tài)樹
@params enhancer 中間件,用于增加redux的處理能力
@return Object store對象
createStore(reducer: Function, preloadedState");
Store
狀態(tài)對象
獲取狀態(tài)樹中的所有狀態(tài)信息
@return Object 狀態(tài)樹信息
getState() => Object
唯一能觸發(fā)狀態(tài)樹中相關(guān)狀態(tài)變化的方法
dispatch會校驗(yàn)對象參數(shù)的正確性,當(dāng)對象沒有type字段時(shí),會造成程序出錯(cuò)
@params action 創(chuàng)建行為的對象
@return Object action對象,非對象時(shí)會觸發(fā)程序錯(cuò)誤,除非使用中間件
dispatch(action: Object) => Object
狀態(tài)樹發(fā)生變化的監(jiān)聽,該方法只單單監(jiān)聽到狀態(tài)樹發(fā)生變化,未能得知變化的內(nèi)容。目前覺得作用并不大
@params listener 監(jiān)聽的回調(diào) @params Function 取消監(jiān)聽的方法 subscribe(listener: Function) => Function
變更狀態(tài)樹中的處理方式,比如在創(chuàng)建createStore后,需要增加某個(gè)的,這個(gè)時(shí)候就需要用到該方法
前面的使用原則中闡述過,store狀態(tài)樹的內(nèi)容是由的返回值組成。因此store狀態(tài)樹的內(nèi)容隨著的變化而變化
@params nextReducer reducer處理函數(shù) replaceReducer(nextReducer)combineReducers
將多個(gè)不同的處理函數(shù)作為對象某個(gè)key的值,合成一個(gè)函數(shù),作為createStore方法的參數(shù)傳遞
@params reducers 由各個(gè)reducer合成的對象
@return Function reducer處理函數(shù)
combineReducers(reducers: Object) => Function
applyMiddleware
用于擴(kuò)展redux的處理能力,作用于createStore函數(shù)的第三個(gè)參數(shù)傳遞
@params ...middleware 中間件參數(shù)
@return Function store事件的處理函數(shù)
applyMiddleware(...middleware) => Function
bindActionCreators
主要用戶簡化dispatch的調(diào)用,經(jīng)過該方法處理后,可以直接調(diào)用該方法返回的函數(shù)或者對象中的方法觸發(fā)store的更新,而不用使用dispatch。該方法可以嵌套使用
@params actionCreators action行為對象或者函數(shù)
@params dispatch 觸發(fā)更新的方法
@return Object | Function
bindActionCreators(actionCreators: Object | Function, dispatch) => Object | Function
API使用示例 redux-2
//定義action
export const add = (text) => ({
type: "ADD",
text
})
export const extendFilter = () => ({
type: "EXTENDSHOW"
})
export const reduce = ()=> ({
type: "REDUCE"
})
export const filter = ()=> ({
type: "SHOW"
})
//reducer的處理
const list = (state = [], action) => {
switch (action.type) {
case "ADD":
return [
...state,
{
id:state.length,
text: action.text
}
]
case "REDUCE":
if (state.length === 0) {
return state
}else {
state.pop()
return [...state]
}
default:
return state //必須有返回內(nèi)容,卻不能undefined、null
}
}
const show = (state = false, action) => {
if (action.type === "SHOW") {
return !state
}
return true
}
const extendShow = (state = false, action) => {
if (action.type === "EXTENDSHOW") {
return !state
}
return true
}
export const rootReducer = combineReducers({
list,
show
})
const showReducer = combineReducers ({
extendShow
})
export const secondReducer = combineReducers({
list,
"show": show,
showReducer
})
//進(jìn)過bindActionCreators處理后,可以直接調(diào)用filterDispatch觸發(fā)更新
const filterDispatch = bindActionCreators(filter,store.dispatch)
//獲取狀態(tài)樹中的指定內(nèi)容
showLabel.innerText = store.getState().show ");"顯示" : "隱藏"
中間件、擴(kuò)展
redux-devtools-extension
該插件主要有助于開發(fā)過程中,查看狀態(tài)樹的狀態(tài)以及變化過程
使用方式:
//安裝
npm i --save-dev redux-devtools-extension
//使用
import { composeWithDevTools } from "redux-devtools-extension"
const store = createStore(rootReducer,composeWithDevTools())
redux-thunk
redux-thunk中間件使redux在dispatch方法中支持異步操作。
實(shí)現(xiàn)原理是向傳遞給dispatch的函數(shù)參數(shù)注入Store對象的dispatch與getState方法,使得可以在函數(shù)內(nèi)部調(diào)用dispatch與getState方法。同時(shí)通過支持使用注入額外的一個(gè)自定義參數(shù)
使用示例 redux-3:
const customObj1 = {
name: "Tom",
age: 18
}
const customObj2 = {
name: "Chen",
age: 20
}
const store = createStore(rootReducer,composeWithDevTools(applyMiddleware(thunk.withExtraArgument(customObj1,customObj2))))
addElement.onclick = () => {
if (inputElement.value.length <= 0) {
return
}
let value = inputElement.value
store.dispatch(function(dispatch,getState) {
//從這里log輸出可知,通過withExtraArgument只支持傳遞一個(gè)參數(shù)
console.log(arguments)// [?, ?, {…}]
console.log(getState()) // {list: Array(0)}
setTimeout(() => {
dispatch(add(value))
console.log(getState()) // {list: Array(1)}
}, 1000)
})
// store.dispatch(addHandle(value))
inputElement.value = ""
}
function addHandle(value) {
return function(dispatch,getState) {
console.log(arguments)
setTimeout(() => {
dispatch(add(value))
}, 1000)
}
}
redux-promise
redux-promise中間件與redux-thunk作用相同,使redux支持異步操作的能力。
在redux中行為創(chuàng)建函數(shù)中,只允許返回同步的對象,然而redux-promise使得行為創(chuàng)建函數(shù)中支持返回promise對象,當(dāng)promise執(zhí)行成功時(shí),觸發(fā)狀態(tài)樹的更新;當(dāng)promise執(zhí)行失敗時(shí),狀態(tài)樹不會發(fā)生任何的變化,也不會導(dǎo)致程序出錯(cuò)
使用示例 redux-4:
export const add = (text) => {
return new Promise((fulfill,reject) => {
setTimeout(() => {
fulfill({
type: "ADD",
text
})
}, 1000);
})
}
export const reduce = ()=> {
return new Promise((fulfill,reject) => {
setTimeout(() => {
reject()
}, 500);
})
}
redux-actions
redux-actions擴(kuò)展主要便于編寫和,從而簡化redux的使用
@params type action中的type字段
@params payloadCreator payloadCreator的處理返回結(jié)果,將成為action的payload字段的內(nèi)容
@params metaCreator metaCreator的處理返回結(jié)果,將成為action的meta字段的內(nèi)容
createAction(type, payloadCreator");
:
export default function createAction(
type,
payloadCreator = value => value, //當(dāng)未設(shè)置該參數(shù)時(shí),會默認(rèn)返回傳遞的參數(shù)
metaCreator
) {
invariant(
isFunction(payloadCreator) || isNull(payloadCreator),
"Expected payloadCreator to be a function, undefined or null"
);
/*
此處檢查payloadCreator函數(shù)的第一個(gè)參數(shù)如果是error將不執(zhí)行該函數(shù),直接返回error
*/
const finalPayloadCreator =
isNull(payloadCreator) || payloadCreator === identity
");typeString = type.toString();
const actionCreator = (...args) => {
const payload = finalPayloadCreator(...args);
//創(chuàng)建action對象
const action = { type };
if (payload instanceof Error) {
action.error = true;
}
if (payload !== undefined) {
//如果是error,則添加特殊的字段
action.payload = payload;
}
if (hasMeta) {
action.meta = metaCreator(...args);
}
return action;
};
actionCreator.toString = () => typeString;
return actionCreator;
}
示例:
const todo = createAction("TODO", name => {
return {name: "action" + name}
}, name => {
return {age: 18}
});
console.log(todo("name"))
結(jié)果:
{type: "TODO", payload: {name: "actionname"}, meta: {age: 18}}
/*
當(dāng)不需要對action的行為參數(shù)進(jìn)行處理時(shí),
可以將payloadCreator設(shè)置為undefined或者null。
同理不需要額外處理其他數(shù)據(jù)時(shí),metaCreator也可以忽略
*/
const todo = createAction("TODO",undefined, name => {
return {age: 18}
})
console.log(todo("name"))
結(jié)果:
{type: "TODO", payload: "name", meta: {age: 18}}
const todo = createAction("TODO")
console.log(todo("name"))
結(jié)果:
{type: "TODO", payload: "name"}
/*
當(dāng)action行為的參數(shù)是error時(shí),action返回的對象中會額外增加error字段,
并且其值為true,而且不會調(diào)用payloadCreator方法
*/
const todo = createAction("TODO", name => {
return {name: "action" + name}
}, name => {
return {age: 18}
});
console.log(todo(new Error("error")))
結(jié)果:
{type: "TODO", payload: Error: error, error: true, meta: {age: 18}}
@params actionMap action的集合
@params ...identityActions action的type,多帶帶定義該字段相當(dāng)于action的參數(shù)不需要進(jìn)過處理轉(zhuǎn)換
@params options action中type的前綴
createActions(actionMap, ...identityActions");
1.createActions中的actionMap與...identityActions");參數(shù),,否則會忽略actionMap(見示例及源碼分析)
2.同時(shí)實(shí)現(xiàn)payloadCreator與metaCreator方法時(shí),需要將其納入[]數(shù)組中(如下示例)
3.當(dāng)沒有定義options,并且創(chuàng)建的action遞歸時(shí),默認(rèn)的使用/
4.createActions生成的遞歸對象的key中使用to-camel-case插件,將其轉(zhuǎn)換為駝峰的方式,但具體action中type保持不變(見示例)
:
function createActions(actionMap, ...identityActions) {
const options = isPlainObject(getLastElement(identityActions))
");"Expected optional object followed by string action types"
);
//如果以identityActions開頭,則直接返回identityActions所生成的
if (isString(actionMap)) {
return actionCreatorsFromIdentityActions(
[actionMap, ...identityActions],
options
);
}
return {
...actionCreatorsFromActionMap(actionMap, options),
...actionCreatorsFromIdentityActions(identityActions, options)
};
}
示例:
//先identityActions在actionMap的情況
export const list = createActions("ADD",{
"REDUCE": value => value
})
console.log(list)
結(jié)果:{add: ?}
const todos = createActions(
{
profile: {
add: name => name,
DELETE_ITEM: [name => ({ name, age: 18 }), name => ({ gender: "female" })]
},
show: name => name
},
"hidden",
{ prefix: "todo", namespace: "-" }
)
console.log(todos.show("name"))
結(jié)果:
{type: "todo-show", payload: "name"}
console.log(todos.profile.deleteItem("name"))
結(jié)果:
{type: "todo-profile-delete", payload: {name: "name", age: 18}, meta: {gender: "female"}}
const todos = createActions("ADD","DELETE")
console.log(todos.add("name"))
結(jié)果:
{type: "ADD", payload: "name"}
@params type action中的type
@params reducer 行為處理函數(shù)
@params defaultState 默認(rèn)值(必須有默認(rèn)值,當(dāng)state未null時(shí),使用defaultState)
handleAction(type,reducer | reducerMap = Identity, defaultState)
使用next、throw處理action行為邏輯是時(shí),可以有效處理action對象中出現(xiàn)Error的情況(createAction中已經(jīng)介紹如何出現(xiàn)Error)
:
export default function handleAction(type, reducer = identity, defaultState) {
const types = toString(type).split(ACTION_TYPE_DELIMITER);
//defaultState指定該參數(shù)是必須的
invariant(
!isUndefined(defaultState),
`defaultState for reducer handling ${types.join(", ")} should be defined`
);
//reducer參數(shù)必須是對象或者函數(shù)
invariant(
isFunction(reducer) || isPlainObject(reducer),
"Expected reducer to be a function or object with next and throw reducers"
);
const [nextReducer, throwReducer] = isFunction(reducer)
");return (state = defaultState, action) => {
const { type: actionType } = action;
if (!actionType || types.indexOf(toString(actionType)) === -1) {
return state;
}
//當(dāng)acton出現(xiàn)Error時(shí)使用throwReducer函數(shù)處理
return (action.error === true ");
示例:
const todoReducer = handleAction("TODO",(state,action)=> ({
name: action.payload
}),"default")
//next、throw的方式
export const err = createAction("ERROR")
export const flag = handleAction("ERROR",{
next(state,action){
console.log("next",state,action)
return !state
},
throw(state,action){
console.log("throw",state,action)
return !state
}
},true)
err(new Error("自定義錯(cuò)誤")) //此時(shí)會執(zhí)行throw方法
@params reducerMap reducer處理函數(shù) @params defaultState 默認(rèn)值(必須有默認(rèn)值) @params options 定義遞歸的前綴(同createActions) handleActions(reducerMap, defaultState, options");
示例:
const todos = handleActions({
"ADD_TODO": (state = [],action) => {
return [
...state,
{
id: action.payload.id,
text: action.payload.text,
completed: false
}
]
},
"TOGGLE_TODO": (state = [],action) => {
return state.map(todo => {
console.log(todo,action)
return (todo.id === action.payload)
");"DELETE_TODO":(state = [], action) => {
state.pop()
return state
}
},[])
//使用map的方式處理
const todos = handleActions(
new Map([
[
// "ADD_TODO",//使用action的type方式
addTodo,//使用action的方式
(state = [], action) => {
return [
...state,
{
id: action.payload.id,
text: action.payload.text,
completed: false
}
];
}
],
[
"TOGGLE_TODO",
(state = [], action) => {
return state.map(todo => {
console.log(todo, action);
return todo.id === action.payload
");
示例 redux-5:
export const promiseAction = createAction("PROMISE", (value) => {
console.log(value)
return new Promise((fulfill,reject) => {
setTimeout(() => {
fulfill(value)
}, 1000);
})
})
react-redux
React框架提供的只是一個(gè)抽象的DOM層,組件間的通訊處理麻煩。react-redux有效的協(xié)助我們處理這些難題。有關(guān) React 介紹可以自行瀏覽官網(wǎng)。
該插件所展示的示例來自于Redux官方提供的todos項(xiàng)目改造而來
使最終的store狀態(tài)樹 在任何被嵌套的組件中都能獲取
示例 redux-6:
const store = createStore(rootReducer)
render(
,
document.getElementById("root")
)
將React組件連接到store狀態(tài)樹
@params mapStateToProps 需要獲取的狀態(tài)樹相關(guān)信息 @params mapDispatchToProps dispath相關(guān)觸發(fā)更新 @params mergeProps 自定義映射到組件props字段的處理 @params options 自定義選項(xiàng) connect(mapStateToProps");
根據(jù)需要從store中獲取相關(guān)字段信息與調(diào)用組件時(shí)所傳遞參數(shù)構(gòu)建對象,對象中的每個(gè)字段都將成為組件的prop,同時(shí)字段中的值也將確定該組件是否需要重新渲染.如果定義mergeProps函數(shù)(見mergeProps方法說明),則作為stateProps參數(shù)
當(dāng)store發(fā)生變化時(shí)會回調(diào)該函數(shù),如果不需要訂閱變化,可設(shè)置為null或undefined
方法內(nèi)不能存在異步的行為,所有的操作都應(yīng)該保持同步
@params state 整個(gè)store的狀態(tài)樹
@params ownProps 調(diào)用該組件時(shí)傳遞的參數(shù)
@return Object
mapStateToProps");
示例 redux-6:
const mapStateToProps = (state, ownProps) => ({ //獲取狀態(tài)樹中的filter字段信息 active: ownProps.filter === state.visibilityFilter })
用于定義觸發(fā)store更新的操作也就是dispatch, 返回對象中的每個(gè)字段都將成為組件的prop中的字段。如果定義mergeProps函數(shù)(見mergeProps方法說明),則作為dispatchProps參數(shù)
當(dāng)未定義該方法時(shí),組件中默認(rèn)接收dispatch參數(shù);一旦定義了該方法,組件中將不接收dispatch參數(shù)。但可以通過手動(dòng)注入的方式向props傳遞dispatch(見示例)
@params dispatch store中觸發(fā)更新的操作
@parmas ownProps 調(diào)用該組件時(shí)傳遞的參數(shù),當(dāng)接收到新的props時(shí)會回調(diào)該函數(shù)
@return Object 必須返回一個(gè)對象,該對象中定義觸發(fā)store更新的操作
mapDispatchToProps");
示例 redux-6:
const mapDispatchToProps = (dispatch, ownProps) => ({
onClick: () => dispatch(setVisibilityFilter(ownProps.filter)),
dispatch //由于定義了mapDispatchToProps函數(shù),組件默認(rèn)不會接收dispatch參數(shù),因此手動(dòng)傳入
})
//當(dāng)不需要獲取相關(guān)信息時(shí),也可以直接返回對象的方式
const increment = () => ({ type: "INCREMENT" })
const decrement = () => ({ type: "DECREMENT" })
const reset = () => ({ type: "RESET" })
const mapDispatchToProps = {
increment,
decrement,
reset
}
自定義映射組件props的操作,如果未實(shí)現(xiàn)該方法,則默認(rèn)實(shí)現(xiàn){ ...ownProps, ...stateProps, ...dispatchProps }
@params stateProps mapStateToProps方法返回對象
@params dispatchProps mapDispatchToProps方法返回對象
@params ownProps 調(diào)用該組件時(shí)傳遞的參數(shù)
@return Object
mergeProps");
一些常用選項(xiàng),具體說明見官方文檔
{ context");待續(xù).....
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/7844.html
摘要:要求通過要求數(shù)據(jù)變更函數(shù)使用裝飾或放在函數(shù)中,目的就是讓狀態(tài)的變更根據(jù)可預(yù)測性單向數(shù)據(jù)流。同一份數(shù)據(jù)需要響應(yīng)到多個(gè)視圖,且被多個(gè)視圖進(jìn)行變更需要維護(hù)全局狀態(tài),并在他們變動(dòng)時(shí)響應(yīng)到視圖數(shù)據(jù)流變得復(fù)雜,組件本身已經(jīng)無法駕馭。今天是 520,這是本系列最后一篇文章,主要涵蓋 React 狀態(tài)管理的相關(guān)方案。 前幾篇文章在掘金首發(fā)基本石沉大海, 沒什么閱讀量. 可能是文章篇幅太長了?掘金值太低了? ...
摘要:傳統(tǒng)框架的缺陷傳統(tǒng)框架的缺陷模型視圖控制器的縮寫即視圖用戶看到并與之交互的界面。即模型是管理數(shù)據(jù)很多業(yè)務(wù)邏輯都在模型中完成。在的三個(gè)部件中,模型擁有最多的處理任務(wù)。所有的狀態(tài),保存在一個(gè)對象里面唯一數(shù)據(jù)源。1、傳統(tǒng)MVC框架的缺陷 模型(model)-視圖(view)-控制器(controller)的縮寫 V即View視圖:用戶看到并與之交互的界面。 M即Model模型是管理數(shù)...
摘要:歸約器函數(shù)負(fù)責(zé)返回應(yīng)用當(dāng)前全局狀態(tài)的表示形式。當(dāng)我們在存儲上發(fā)送操作時(shí)將使用應(yīng)用的當(dāng)前狀態(tài)和導(dǎo)致狀態(tài)更新的操作來調(diào)用此歸約器函數(shù)。回到我們的歸約器我們可以檢查的動(dòng)作類型并采取適當(dāng)?shù)牟襟E創(chuàng)建下一個(gè)狀態(tài)。我們將處理動(dòng)作創(chuàng)造者中歸約器的副作用。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3811原文:https://www.ful...
摘要:本文轉(zhuǎn)載自眾成翻譯譯者鏈接原文今天,我們在方法中使用中間件來管理我們的代碼中的復(fù)雜狀態(tài)變化。中間件是一個(gè)很好的地方。我們中間件我們將實(shí)現(xiàn)一些中間件它將代表我們處理異步請求。中間件位于動(dòng)作和歸并器之間。讓我們創(chuàng)建我們的第一個(gè)中間件。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3810原文:https://www.fullsta...
閱讀 2171·2020-06-12 14:26
閱讀 2477·2019-08-29 16:41
閱讀 1885·2019-08-29 15:28
閱讀 2448·2019-08-26 13:43
閱讀 753·2019-08-26 13:37
閱讀 2773·2019-08-23 18:13
閱讀 2791·2019-08-23 15:31
閱讀 1014·2019-08-23 14:10