歡迎關注公眾號:n平方 如有問題或建議,請後臺留言,我會盡力解決你的問題。
簡介
Redux是針對JavaScript應用的可預測狀態容器。
如果熟悉設計模式之觀察者模式理解起來就簡單了。就是將你在其他元件中需要用到的資料放到一個容器中,那麼元件就可以從其中取放資料的東西就是redux的工作。
特性:
- 可預測性(predictable): 因為Redux用了reducer與純函式(pure function)的概念,每個新的state都會由舊的state建來一個全新的state。因而所有的狀態修改都是”可預測的”。
- 狀態容器(state container): state是集中在單一個物件樹狀結構下的單一store,store即是應用程式領域(app domain)的狀態集合。
- JavaScript應用: 這說明Redux並不是單指設計給React用的,它是獨立的一個函式庫,可通用於各種JavaScript應用。
核心概念
action:是把資料從應用(譯者注:這裡之所以不叫 view 是因為這些資料有可能是伺服器響應,使用者輸入或其它非 view 的資料 )傳到 store 的有效載荷。它是 store 資料的唯一來源。一般來說你會通過 store.dispatch() 將 action 傳到 store。
**reducer:**指定了應用狀態的變化如何響應 actions,併傳送到 store 的,記住 actions 只是描述了有事情發生了這一事實,並沒有描述應用如何更新 state。
store: store就是把action和reducer聯絡到一起的物件,store本質上是一個狀態樹,儲存了所有物件的狀態。任何UI元件都可以直接從store訪問特定物件的狀態。 Store 有以下職責:
- 維持應用的 state;
- 提供
getState()
方法獲取 state; - 提供
dispatch(action)
方法更新 state; - 通過
subscribe(listener)
註冊監聽器; - 通過
subscribe(listener)
返回的函式登出監聽器。 再次強調一下 Redux 應用只有一個單一的 store。
基本原理
這個資料流的位於最中心的設計是一個AppDispatcher(應用傳送器),你可以把它想成是個傳送中心,不論來自元件何處的動作都需要經過它來傳送。每個store會在AppDispatcher上註冊它自己,提供一個callback(回撥),當有動作(action)發生時,AppDispatcher(應用傳送器)會用這個回撥函式通知store。
由於每個Action(動作)只是一個單純的物件,包含actionType(動作型別)與資料(通常稱為payload),我們會另外需要Action Creator(動作建立器),它們是一些輔助函式,除了建立動作外也會把動作傳給Dispatcher(傳送器),也就是呼叫Dispatcher(傳送器)中的dispatch方法。
Dispatcher(傳送器)的用途就是把接收到的actionType與資料(payload),廣播給所有註冊的callbacks。它這個設計並非是獨創的,這在設計模式中類似於pub-sub(釋出-訂閱)系統,Dispatcher則是類似Eventbus的概念。
基本使用
安裝
npm install --save react-redux
npm install --save-dev redux-devtools
複製程式碼
例項 主要是理解觀察者模式,以及結合原理圖先理解 redux的action,reducer,store基本運作。
import { createStore } from 'redux'
/**
* This is a reducer, a pure function with (state, action) => state signature.
* It describes how an action transforms the state into the next state.
*
* The shape of the state is up to you: it can be a primitive, an array, an object,
* or even an Immutable.js data structure. The only important part is that you should
* not mutate the state object, but return a new object if the state changes.
*
* In this example, we use a `switch` statement and strings, but you can use a helper that
* follows a different convention (such as function maps) if it makes sense for your
* project.
*/
/**
* 來源:官網:https://github.com/reduxjs/redux
*
* 第一步:定義reducer
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
// Create a Redux store holding the state of your app.
// Its API is { subscribe, dispatch, getState }.
//第二步:根據reducer規則生成store
let store = createStore(counter)
// You can use subscribe() to update the UI in response to state changes.
// Normally you'd use a view binding library (e.g. React Redux) rather than subscribe() directly.
// However it can also be handy to persist the current state in the localStorage.
//第三步:定義資料(即state)變化之後的派發規則
store.subscribe(() => console.log(store.getState()))
store.subscribe(() => console.log(store.getState()))
store.subscribe(() => console.log(store.getState()))
// The only way to mutate the internal state is to dispatch an action.
// The actions can be serialized, logged or stored and later replayed.
//第四步:觸發資料變化
store.dispatch({ type: 'INCREMENT' })
// 1
store.dispatch({ type: 'INCREMENT' })
// 2
store.dispatch({ type: 'DECREMENT' })
// 1
複製程式碼
常規使用
一般的檔案結構,基本就是store目錄下
actions的操作 user.js:主要包含user模組下的action操作。
import * as types from '../constants/types'
export function loginSuccess(data) {
return {
type: types.LOGOIN_SUCCESS,
payload: data
}
}
export function logOut() {
return {
type: types.LOGOUT
}
}
複製程式碼
reducers的操作 module/user.js:定義
import * as types from '../../constants/types';
export function user(state = 0,action){
switch(action.type) {
case types.LOGOIN_SUCCESS:
console.log("user......"+ action.payload);
return state+10;
case types.LOGOUT:
return state - 10;
default:
return state;
}
}
複製程式碼
index.js 將所有reducers的集合在一起。
import { combineReducers } from 'redux'
import { user } from './module/user'
const rootReducer = combineReducers({
/* your reducers */
user
})
export default rootReducer
複製程式碼
store的操作
import { createStore } from 'redux'
import rootReducer from './reducers'
export default function configureStore(initialState) {
const store = createStore(rootReducer,initialState,
window.devToolsExtension ? window.devToolsExtension() : undefined
)
return store
}
複製程式碼
元件中的操作(簡單)
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import ComA from './ComA'
import ComB from './ComB'
import * as userInfoActions from '../store/actions/user'
class BodyIndex extends React.Component {
componentDidMount() {
this.props.userInfoActions.loginSuccess({
id:'呵呵呵呵',
username: 'bibibiibibi'
})
}
render() {
return (
<div>
<p>Hello world</p>
<ComA user={this.props.user}/>
<ComB user= {this.props.user} />
</div>
)
}
}
function mapStateToProps(state) {
console.log("mapStateToProps...."+state);
return {
user: state.user.userInfo
}
}
function mapDispatchToProps(dispatch) {
return {
userInfoActions: bindActionCreators(userInfoActions,dispatch)
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(BodyIndex)
複製程式碼
元件中的操作(常規) 使用connect 這樣子可以省去mapDispatchToProps,mapDispatchToProps的操作。
import React from 'react';
import { connect } from 'react-redux';
import { addComment } from '../store/actions/comment'
@connect(
state => ({comment:state.comments.comment}),
{ addComment }
)
class TestCom extends React.Component {
componentDidMount() {
this.props.addComment({
comment: 100
})
}
render() {
console.log("render...."+this.props.comment);
return (
<div>
<p>TestCom.... {this.props.comment} </p>
</div>
)
}
}
export default TestCom;
複製程式碼
本文demo
總結
最後,如果對 Java、大資料感興趣請長按二維碼關注一波,我會努力帶給你們價值。覺得對你哪怕有一丁點幫助的請幫忙點個贊或者轉發哦。