前言
一直是Redux的死忠黨,但使用過Vuex後,感嘆於Vuex上手之快,於是萌生了寫一個能在React裡使用的類Vuex庫,暫時取名Ruex。
如何使用
一:建立Store例項:
與vuex一樣,使用單一狀態樹(一個物件)包含全部的應用層級狀態(store)。
store可配置state,mutations,actions和modules屬性:
state
:存放資料mutations
:更改state的唯一方法是提交 mutationactions
:Action 提交的是 mutation,而不是直接變更狀態。Action 可以包含任意非同步操作,觸發mutation,觸發其他actions。
支援中介軟體:中介軟體會在每次mutation觸發前後執行。
store.js:
import {createStore} from `ruex`
const state = {
total_num:1111,
}
const mutations = {
add(state,payload){
state.total_num += payload
},
double(state,payload){
state.total_num = state.total_num*payload
},
}
const actions = {
addAsync({state,commit,rootState,dispatch},payload){
setTimeout(()=>{
commit(`add`,payload)
},1000)
},
addPromise({state,commit,rootState,dispatch},payload){
return fetch(`https://api.github.com/search/users?q=haha`).then(res=>res.json())
.then(res=>{
commit(`add`,1)
dispatch(`addAsync`,1)
})
},
doubleAsync({state,commit,rootState,dispatch},payload){
setTimeout(()=>{
commit(`double`,2)
},1000)
},
doublePromise({state,commit,rootState,dispatch},payload){
return fetch(`https://api.github.com/search/users?q=haha`).then(res=>res.json())
.then(res=>{
commit(`double`,2)
dispatch(`doubleAsync`,2)
})
},
}
// middleware
const logger = (store) => (next) => (mutation,payload) =>{
console.group(`before emit mutation `,store.getState())
let result = next(mutation,payload)
console.log(`after emit mutation`, store.getState())
console.groupEnd()
}
// create store instance
const store = createStore({
state,
mutations,
actions,
},[logger])
export default store
複製程式碼
將Store例項繫結到元件上
ruex提供Provider方便store例項註冊到全域性context上。類似react-redux的方式。
App.js:
import React from `react`
import {Provider} from `ruex`
import store from `./store.js`
class App extends React.Component{
render(){
return (
<Provider store={store} >
<Child1/>
</Provider>
)
}
}
複製程式碼
使用或修改store上資料
store繫結完成後,在元件中就可以使用state上的資料,並且可以通過觸發mutation或action修改state。具體的方式參考react-redux的繫結方式:使用connect高階元件。
Child1.js:
import React, {PureComponent} from `react`
import {connect} from `ruex`
class Chlid1 extends PureComponent {
state = {}
constructor(props) {
super(props);
}
render() {
const {
total_num,
} = this.props
return (
<div className=``>
<div className="">
total_num: {total_num}
</div>
<button onClick={this.props.add.bind(this,1)}>mutation:add</button>
<button onClick={this.props.addAsync.bind(this,1)}>action:addAsync</button>
<button onClick={this.props.addPromise.bind(this,1)}>action:addPromise</button>
<br />
<button onClick={this.props.double.bind(this,2)}>mutation:double</button>
<button onClick={this.props.doubleAsync.bind(this,2)}>action:doubleAsync</button>
<button onClick={this.props.doublePromise.bind(this,2)}>action:doublePromise</button>
</div>)
}
}
const mapStateToProps = (state) => ({
total_num:state.total_num,
})
const mapMutationsToProps = [`add`,`double`]
const mapActionsToProps = [`addAsync`,`addPromise`,`doubleAsync`,`doublePromise`]
export default connect(
mapStateToProps,
mapMutationsToProps,
mapActionsToProps,
)(Chlid1)
複製程式碼
API:
mapStateToProps
:將state上的資料繫結到當前元件的props上。mapMutationsToProps
: 將mutation繫結到props上。例如:呼叫時通過this.props.add(data)的方式即可觸發mutation,data引數會被mutaion的payload引數接收。mapActionsToProps
: 將action繫結到props上。
內部實現
-
ruex內部使用immer維護store狀態更新,因此在mutation中,可以通過直接修改物件的屬性更改狀態,而不需要返回一個新的物件。例如:
const state = { obj:{ name:`aaaa` } } const mutations = { changeName(state,payload){ state.obj.name = `bbbb` // instead of // state.obj = {name:`bbbb`} }, } 複製程式碼
-
支援modules(暫不支援namespace)
-
支援中介軟體。注:actions已實現類似redux-thunk的功能
尾
歡迎提issue star