1洋幻、為什么要用redux
在React中炭玫,數(shù)據(jù)在組件中是單向流動的脑又,數(shù)據(jù)從一個方向父組件流向子組件(通過props),所以,兩個非父子組件之間通信就相對麻煩泞边,redux的出現(xiàn)就是為了解決state里面的數(shù)據(jù)問題
2该押、Redux設計理念
Redux是將整個應用狀態(tài)存儲到一個地方上稱為store,里面保存著一個狀態(tài)樹store tree,組件可以派發(fā)(dispatch)行為(action)給store,而不是直接通知其他組件,組件內部通過訂閱store中的狀態(tài)state來刷新自己的視圖阵谚。
3蚕礼、Redux三大原則
- 1 唯一數(shù)據(jù)源
- 2 保持只讀狀態(tài)
- 3 數(shù)據(jù)改變只能通過純函數(shù)來執(zhí)行
1唯一數(shù)據(jù)源
整個應用的state都被存儲到一個狀態(tài)樹里面,并且這個狀態(tài)樹梢什,只存在于唯一的store中
2保持只讀狀態(tài)
state是只讀的奠蹬,唯一改變state的方法就是觸發(fā)action,action是一個用于描述以發(fā)生時間的普通對象
3數(shù)據(jù)改變只能通過純函數(shù)來執(zhí)行
使用純函數(shù)來執(zhí)行修改嗡午,為了描述action如何改變state的囤躁,你需要編寫reducers
或許你讀到這已經(jīng)不知所云了,沒事這只是讓你了解一些redux到底是干嘛的荔睹,后面或詳細的講解各個部分的作用狸演,并且會講解redux實現(xiàn)原理
4、Redux概念解析
4.1 Store
- store就是保存數(shù)據(jù)的地方僻他,你可以把它看成一個數(shù)據(jù)宵距,整個應用智能有一個store
- Redux提供createStore這個函數(shù),用來生成Store
import {createStore} from 'redux'
const store=createStore(fn);
4.2 State
state就是store里面存儲的數(shù)據(jù)吨拗,store里面可以擁有多個state消玄,Redux規(guī)定一個state對應一個View,只要state相同,view就是一樣的丢胚,反過來也是一樣的翩瓜,可以通過store.getState( )獲取
import {createStore} from 'redux'
const store=createStore(fn);
const state=store.getState()
4.3 Action
state的改變會導致View的變化,但是在redux中不能直接操作state也就是說不能使用this.setState來操作携龟,用戶只能接觸到View兔跌。在Redux中提供了一個對象來告訴Store需要改變state。Action是一個對象其中type屬性是必須的峡蟋,表示Action的名稱坟桅,其他的可以根據(jù)需求自由設置。
const action={
type:'ADD_TODO',
payload:'redux原理'
}
在上面代碼中蕊蝗,Action的名稱是ADD_TODO仅乓,攜帶的數(shù)據(jù)是字符串‘redux原理’,Action描述當前發(fā)生的事情蓬戚,這是改變state的唯一的方式
4.4 store.dispatch( )
store.dispatch( )是view發(fā)出Action的唯一辦法
store.dispatch({
type:'ADD_TODO',
payload:'redux原理'
})
store.dispatch接收一個Action作為參數(shù)夸楣,將它發(fā)送給store通知store來改變state。
4.5 Reducer
Store收到Action以后,必須給出一個新的state豫喧,這樣view才會發(fā)生變化石洗。這種state的計算過程就叫做Reducer。
Reducer是一個純函數(shù)紧显,他接收Action和當前state作為參數(shù)讲衫,返回一個新的state
注意:Reducer必須是一個純函數(shù),也就是說函數(shù)返回的結果必須由參數(shù)state和action決定孵班,而且不產生任何副作用也不能修改state和action對象
const reducer =(state,action)=>{
switch(action.type){
case ADD_TODO:
return newstate;
default return state
}
}
5涉兽、Redux源碼
里面的注釋就是我一步一步的分析,有點懶沒有把代碼拆分出來給你們看
let createStore = (reducer) => {
let state;
//獲取狀態(tài)對象
//存放所有的監(jiān)聽函數(shù)
let listeners = [];
let getState = () => state;
//提供一個方法供外部調用派發(fā)action
let dispath = (action) => {
//調用管理員reducer得到新的state
state = reducer(state, action);
//執(zhí)行所有的監(jiān)聽函數(shù)
listeners.forEach((l) => l())
}
//訂閱狀態(tài)變化事件篙程,當狀態(tài)改變發(fā)生之后執(zhí)行監(jiān)聽函數(shù)
let subscribe = (listener) => {
listeners.push(listener);
}
dispath();
return {
getState,
dispath,
subscribe
}
}
let combineReducers=(renducers)=>{
//傳入一個renducers管理組花椭,返回的是一個renducer
return function(state={},action={}){
let newState={};
for(var attr in renducers){
newState[attr]=renducers[attr](state[attr],action)
}
return newState;
}
}
export {createStore,combineReducers};
6、Redux使用案例
html代碼
<div id="counter"></div>
<button id="addBtn">+</button>
<button id="minusBtn">-</button>
js代碼
function createStore(reducer) {
var state;
var listeners = [];
var getState = () => state;
var dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(l=>l());
}
var subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter((l) => l != listener)
}
}
dispatch();
return {
getState, dispatch, subscribe
}
}
var reducer = (state = 0, action) => {
if (!action) return state;
console.log(action);
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
var store = createStore(reducer);
store.subscribe(function () {
document.querySelector('#counter').innerHTML = store.getState();
});
document.querySelector('#addBtn').addEventListener('click', function () {
store.dispatch({type: 'INCREMENT'});
});
document.querySelector('#minusBtn').addEventListener('click', function () {
store.dispatch({type: 'DECREMENT'});
});