store 是應用狀態 state 的管理者,包含下列四個函數:
一、getState() 獲取整個 state
二、dispatch(action) 觸發 state 改變的【惟一途徑】
三、subscribe(listener) 訂閱state改變
四、replaceReducer(nextReducer)javascript
如何初始化?前端
複製代碼
如何獲取statevue
var state = store.getState()
複製代碼
作什麼用的?
是一個對象,裏面包含type字段和payload,type是給Reducer修改state的時候判斷用的,payload是要修改的數據java
{
type: 'ADD_TODO',
payload: {
id: 1,
content: '待辦事項1',
completed: false
}
}
複製代碼
負責複用action對象的,能夠給payload賦值不一樣數據react
function addTodo(content) {
return {
type: 'ADD_TODO',
payload: {
id: id++,
content: content, // 待辦事項內容
completed: false // 是否完成的標識
}
}
}
複製代碼
action是能夠異步的,如何異步呢?git
export const INCREMENT_COUNTER = 'INCREMENT_COUNTER';
export const DECREMENT_COUNTER = 'DECREMENT_COUNTER';
export function increment() {
return {
type: INCREMENT_COUNTER
};
}
export function decrement() {
return {
type: DECREMENT_COUNTER
};
}
//這裏正常來講若是不給redux添加中間件的話這樣會報錯,可是引入redux-thunk這個中間件,就能夠改變原來的dispatch處理方式,支持返回函數而且進行異步處理,而且給返回的函數注入dispatch, getState
export function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}
export function incrementAsync(delay = 1000) {
return (dispatch) => {
setTimeout(() => {
dispatch(increment());
}, delay);
};
}
複製代碼
那麼redux-thunk內部又是如何實現的呢?如下是源碼分析:github
//redux添加中間件源碼
export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
`Dispatching while constructing your middleware is not allowed. ` +
`Other middleware would not be applied to this dispatch.`
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
//這裏負責將getState和dispatch注入
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
return enhancer(createStore)(reducer, preloadedState)
//redux-thunk源碼
//傳入一些額外的
function createThunkMiddleware(extraArgument) {
// 這段寫法的意思是: 至關於函數柯里化將多個參數層層包裝
// return function ({
// dispatch,
// getState
// }) {
// 根據上面redux源碼 next就是 store.dispatch
// return function (next) {
// 這個時候實際返回的dispatch就被改寫成這個了: 參考redux源碼:dispatch = compose(...chain)(store.dispatch)
// return function (action) {
// 而後在這裏傳入action creator 就能夠處理函數和對象兩種狀況下而後進行異步
// if (typeof action === 'function') {
// return action(dispatch, getState, extraArgument);
// }
// return next(action);
// }
// }
// }
return ({ dispatch, getState }) => next => action => {
//判斷
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
複製代碼
做用:修改state
如何觸發:用戶每次 dispatch(action) 後,都會觸發 reducer 的執行
redux
reducer 的實質是一個函數,根據 action.type 來更新 state 並返回 nextStateapi
最後會用 reducer 的返回值 nextState 徹底替換掉原來的 statebash
注意:上面的這個 「更新」 並非指 reducer 能夠直接對 state 進行修改 Redux 規定,須先複製一份 state,在副本 nextState 上進行修改操做 例如,可使用 lodash 的 cloneDeep,也可使用 Object.assign / map / filter/ ... 等返回副本的函數
Reducer 必須是同步的純函數
如何將react和redux結合起來? 須要react-redux
react-redux模塊用來作什麼用?
redux是一個獨立的庫,這個庫其實能夠用在angular,vue等前端框架中,因此要使用在react中須要經過react-redux作一個轉換
react-redux提供了三個api
connect()
這個方法用來負責將react組件和redux store鏈接起來
經過什麼樣子的方式把這兩個鏈接起來?
如下是connect方法須要傳入的參數
function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?) 複製代碼
mapStateToProps:將redux中的state映射到props中去
示例:
//這一段是
export function increment() {
return {
type: INCREMENT_COUNTER
};
}
export function decrement() {
return {
type: DECREMENT_COUNTER
};
}
export function incrementIfOdd() {
return (dispatch, getState) => {
const { counter } = getState();
if (counter % 2 === 0) {
return;
}
dispatch(increment());
};
}
export function incrementAsync(delay = 1000) {
return (dispatch) => {
setTimeout(() => {
dispatch(increment());
}, delay);
};
}
//組件映射代碼
import { bindActionCreators } from 'redux';
//映射state的某些字段到props中
function mapStateToProps(state) {
return {
counter: state.counter
};
}
//映射dispatch到組件的props
function mapDispatchToProps(dispatch) {
return bindActionCreators(CounterActions, dispatch);
}
//將組件傳入其中映射
export default connect(
mapStateToProps,
mapDispatchToProps
)(Counter);
//組件內部調用
const {
increment,
incrementIfOdd,
incrementAsync,
decrement,
counter
} = props;
複製代碼
以上源碼中存在一個bindActionCreators函數,這個函數來自redux函數庫
如下經過源碼講解一下幹什麼用的
function bindActionCreators(actionCreators, dispatch) {
//若是傳入的是一個函數則調用bindActionCreator函數進行包裝,這樣返回給組件的函數只要調用就能夠觸發state更新
if (typeof actionCreators === 'function') {
return bindActionCreator(actionCreators, dispatch)
}
if (typeof actionCreators !== 'object' || actionCreators === null) {
throw new Error(
`bindActionCreators expected an object or a function, instead received ${ actionCreators === null ? 'null' : typeof actionCreators }. ` +
`Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?`
)
}
//若是是一個對象,就遍歷鍵值進行包裝而後返回組合好的對象
const keys = Object.keys(actionCreators)
const boundActionCreators = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
const actionCreator = actionCreators[key]
if (typeof actionCreator === 'function') {
boundActionCreators[key] = bindActionCreator(actionCreator, dispatch)
}
}
return boundActionCreators
}
//包裝action creator函數爲直接使用dispatch觸發更改的函數
function bindActionCreator(actionCreator, dispatch) {
return function() {
return dispatch(actionCreator.apply(this, arguments))
}
}
複製代碼
根據源碼來看,這個函數的做用就是將dispatch和actionCreator包裝成一個接受單一參數觸發更新store的方法,簡化書寫,也就是函數的柯里化的應用。
Provider
這個標籤使得通過connect函數包裝的組件能夠得到store
正常來講,一個被connect包裝過的組件只能用在裏面
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import { App } from './App'
import createStore from './createReduxStore'
const store = createStore()
ReactDOM.render(
<Provider store={store}> <App /> </Provider>,
document.getElementById('root')
)
複製代碼
connectAdvanced
它是一個將 React 組件鏈接到 Redux store 的函數。這個函數是 connect() 的基礎,可是對於如何把state, props, 和 dispatch 組合到最後的 props 中,則不那麼自覺得是。它不對默認值或結果的記錄作任何假設,而是將這些責任留給調用者。
意思就是不會提供默認組合的方法,而是把這些方法讓開發者實現,實現更靈活的擴展
github.com/kenberkeley…
react-redux.js.org/
www.redux.org.cn/