smox
v2.5.5
Published
Fast 1kB state management that path-updating.
Downloads
24
Readme
Use
npm i smox -S
import { Smox } from 'smox'
const state = {
count: 0,
}
const actions = {
up(state) {
state.count++
},
down(state) {
state.count--
},
}
const effects = {
async upAsync(actions) {
await new Promise(t => setTimeout(t, 1000))
actions.up()
},
}
const store = new Smox({ state, actions, effects })
以上,smox 的部分就结束啦,创建了一个 store
React
对外暴露 Provider 和 Consumer 组件,可以方便的用于 react 组件中
为什么使用 render props 而不是 HOC?由于 hooks API 的出现,导致 HOC 只适用于 class API,render props 可同时适用于 class 和 function,是最合适的拓展机制
其中,Provider 组件接受 store 作为参数,而 Consumer 可以接受到 path 限定过的 part store
import { Provider, Consumer } from 'smox'
class App extends React.Component {
render() {
return (
<>
<Consumer>
{({ state, actions, effects }) => (
<>
<h1>{state.count}</h1>
<button onClick={actions.up}>+</button>
<button onClick={actions.down}>-</button>
<button onClick={effects.upAsync}>x</button>
</>
)}
</Consumer>
</>
)
}
}
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
)
Path
path 是一个匹配机制,举例说明:
const state = {
counter: {
count: 0,
},
}
const actions = {
counter: {
up(state, data) {
//此处的 state 为同路径的 { count:0 }
state.count += data
},
down(state, data) {
state.count -= data
},
},
}
const effects = {
counter: {
async upAsync(actions) {
//此处的 actions 为同路径的 { up(), down() }
await new Promise(t => setTimeout(t, 1000))
actions.up()
},
},
}
可以看到,跟对象下面的 counter 对象,此时的 path 是 /counter
现在我们有个 <App />
跟组件,它默认匹配全局的 store,此时它的 path 是 /
然后 <App />
有个子组件 <Counter />
,这个组件的 path 是 /counter
,那么它匹配的就是 store 对象下面的 counter 对象的属性和方法
function App() {
//跟组件匹配的是全局 store
return <Counter />
}
function Counter() {
return (
<Consumer>
{({ state, actions, effects }) => (
/*此处是 counter 对象中的
{ state:{ count },
actions:{ up(), down() },
effects:{ asyncUp() }
}*/
<>
<h1>{state.count}</h1>
<button onClick={actions.up}>+</button>
<button onClick={actions.down}>-</button>
<button onClick={effects.upAsync}>x</button>
</>
)}
</Consumer>
)
}
通过这个约定,我们不需要关心 store 的拆分,只需要按照规定安排 store 和 组件即可
Proxy、async/await
Proxy、async/await 可以使得 actions 代码同步,更好看
const actions = {
up(state) {
state.count += 1
state.count += 2
},
}
使用这个 polyfill 可以兼容 ie9+
同时 effects 下面,配合 async/await,也能同步的编写逻辑
const effects = {
async upAsync(actions) {
await new Promise(t => setTimeout(t, 1000))
actions.up()
actions.down()
},
}
Immed
immed 是 smox 内部的一个子包,它和 immer 类似,但是和 path 结合使用,性能更好
import { produce } from 'smox'
class App extends React.Component {
onClick = () => {
this.setState(
produce(this.state, draft => {
draft.count++
})
)
}
}
export default App
Demo
License
MIT