在React裡使用”Vuex”

哈哈TT發表於2019-01-30

前言

一直是Redux的死忠黨,但使用過Vuex後,感嘆於Vuex上手之快,於是萌生了寫一個能在React裡使用的類Vuex庫,暫時取名Ruex

如何使用

一:建立Store例項:

與vuex一樣,使用單一狀態樹(一個物件)包含全部的應用層級狀態(store)。

store可配置state,mutations,actions和modules屬性:

  • state:存放資料
  • mutations:更改state的唯一方法是提交 mutation
  • actions: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上。

內部實現

  1. ruex內部使用immer維護store狀態更新,因此在mutation中,可以通過直接修改物件的屬性更改狀態,而不需要返回一個新的物件。例如:

    const state = {
    	obj:{
    		name:`aaaa`
    	}
    }
    const mutations = {
    	changeName(state,payload){
    		state.obj.name = `bbbb`
    		// instead of 
    	    // state.obj = {name:`bbbb`}
    	},
    }
    複製程式碼
  2. 支援modules(暫不支援namespace)

  3. 支援中介軟體。注:actions已實現類似redux-thunk的功能

歡迎提issue star

Github

相關文章