本文开发的reacx状态库,是为了加深对状态管理库的理解,目前尚未运用商业项目中, 仅供参考。
项目目录
其余才用create-react-app创建
+ src
App.js
HelloWorld.js
index.js
reatx.js
store.js
reatx.js
react版本的vuex状态管理库
import React from 'react'
import PropTypes from 'prop-types'
const isObject = (v) => v && typeof v === 'object'
class Reatx {
constructor (options) {
this.state = options.state
this._actions = options.actions
this._mutations = options.mutations
this._listeners = []
}
subscribe (listener) {
this._listeners.push(listener)
}
commit (type, payload) {
this._mutations[type].call(this, this.state, payload)
this._listeners.forEach(listener => {
listener()
})
}
dispatch (type) {
this._actions[type](this)
}
}
export class Provider extends React.Component{
static childContextTypes = {
store: PropTypes.object
}
getChildContext(){
return {store: this.store}
}
constructor(props, context){
super(props, context)
this.store = props.store
}
render(){
return this.props.children
}
}
export const connect = (stateObj) => {
return (App) => {
return class WrapperApp extends React.Component {
static contextTypes = {
store: PropTypes.object
}
constructor (props, context) {
super(props, context)
this.state = {
store: context.store
}
this.unsubscribe = context.store.subscribe(() => {
this.setState({})
})
this._mappedProps = this.getProps()
}
componentWillUnmount () {
this.unsubscribe()
}
shouldComponentUpdate () {
let preProps = this._mappedProps
let nextProps = this.getProps()
console.log(preProps, nextProps)
if (isObject(preProps) && isObject(nextProps)) {
let nextKeys = Object.keys(nextProps)
for (let i = 0, len = nextKeys.length; i < len; i++) {
let nextK = nextKeys[i]
if (nextProps[nextK] !== preProps[nextK]) {
this._mappedProps = nextProps
return true
}
}
}
console.log(false)
return false
}
getProps () {
let _mappedProps = {}
let copy = JSON.parse(JSON.stringify(this.state.store.state))
Object.keys(stateObj).forEach(k => {
_mappedProps[k] = stateObj[k].call(this, copy)
})
return _mappedProps
}
render(h) {
return (
<App { ...this.state } { ...this._mappedProps }/>
)
}
}
}
}
export default Reatx
webpack打包入口 index.js 。
- Vue 通过提供 beforeCreate 的 mixin 勾子,可以将store挂载在每个组件实例的 $store 属性中。
- react不提供这个勾子。而是通过封装Provider组件,将store存储在context中,从而使得每个组件可以获得仓库的引用。
import React from 'react'
import { render } from 'react-dom'
import App from './App'
import store from './store'
import { Provider } from './reatx'
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
根组件App.js
import React from 'react'
import HelloWorld from './HelloWorld'
class App extends React.Component {
render () {
return <HelloWorld />
}
}
export default App
页面组件HelloWorld.js
- Vue提供computed选项,通过mapState,将store中的state映射到组件的实例中。
- React更加灵活,提供了高阶组件,设计一个connect高阶组件,第一个入参数相当于vuex中computed选项中的mapState,将仓库中的state映射到组件的props中。
import React from 'react'
import { connect } from './reatx'
class HelloWorld extends React.Component {
render () {
let { store } = this.props
return (
<div>
<p>{ this.props.obj.num }</p>
<button onClick={e => {
store.dispatch('add')
}}>增加</button>
<button onClick={e => store.dispatch('delete')}>减少</button>
</div>
)
}
}
export default connect({
obj: (state) => state.obj
})(HelloWorld)
实例仓库, api与vuex保持一致。
- dispatch一个action
- 在action中触发mutation
import Reatx from './reatx'
const store = new Reatx({
state: {
obj: {
num: 0
},
userInfo: {},
phone: '',
latitude: '',
longitude: '',
channel: ''
},
actions: {
add (store) {
store.commit('ADD')
},
delete (store) {
store.commit('DELETE')
}
},
mutations: {
ADD (state, payload) {
state.obj.num = state.obj.num + 1
},
DELETE (state, payload) {
state.obj.num = state.obj.num - 1
}
}
})
export default store