wallant
Version:
Persistant, auto-validate, and computed state container
304 lines (244 loc) • 6 kB
Markdown
<p>
<img src="https://img.shields.io/npm/dt/wallant.svg?colorB=8bc34a"/>
<img src="https://img.shields.io/npm/v/wallant.svg?colorB=f44336"/>
</p>
<p align="center">
<img src="https://i.imgur.com/M1JFh4j.png" width="400">
</p>
<p align="center">Persistant, auto-validate, and predictable state container for React Native</p>
---
<a href="https://github.com/e1016/wallant/blob/master/es_README.md">Lee la documentación en español</a>
---
## install
`npm i -s wallant`
## use
basic configuration in `/ReactNativeApp/src/Store.js`
```js
import Wallant from 'wallant'
const store = new Wallant({
persistant: true, // <- persistant state decribed bellow
state: {
count: 0
},
actions: {
add () {
this.setState({
count: this.state.count + 1
})
},
sub () {
this.setState({
count: this.state.count - 1
})
}
}
})
export default store
```
now we linking store to the component
```js
// import react and stuffs...
import store from './src/Store'
class App extends Component {
componentDidMount () {
store.use(this)
}
render () {
return (
<View style={ styles.container }>
<Text>{ store.state.count }</Text>
<Button
title="add to the counter"
onPress={ store.action.add }/>
</View>
)
}
}
```
Store take control of component when you link it on `componentDidMount`, in other stores is used a `<Provider>` solution, but we want get control from linking store, and set reactive state only in neccessary components.
---
Now, all this is a simple store, but wallant can do more interesting things...
## persistant
> [ DEPRECATED in 2.0 ] This feature save state automatically and allow restore it when app starts, you only need declare `persistant` as `true` in Wallant constructor.
We detect an important performance leak for automatically save state in phone some times, for example, when you set state on change text event. We resolve this creating a `commit` behavior, `persistant: true` still working. TextInput example implementation.
```js
// store
const store = new Wallant({
// [...]
persistant: true,
// [...]
})
<TextInput
onEndEditing={() =>
store.commit() // saves state in storage
}
onChangeText={text =>
store.action.updateText(text) // update state
}/>
```
default state is loaded to store on first time.
You can detect if store state is restored checking for `store.restored` is a boolean, meanwhile store.restored is false, state is restoring, and is true after that.
```js
render () {
return store.restored ? (
<View>
<Text>State is restored!</Text>
</View>
) : (
<View>
<Text>State is restoring...</Text>
</View>
)
}
```
Reset state it's easy, use `store.resetState()` and it's all.
---
## actions
Actions allow you modify state, `this` make reference to `store`.
```js
const store = new Wallant({
state: {
count: 0
},
actions: {
add () {
// tip! you can use 'ss' method
// instead of 'setState', there
// is not diferences, it's only
// a short hand
this.ss({
count: this.state.count + 1
})
}
}
})
```
Use a callback for update state
```js
// ss === setState
this.ss(state => {
state.someKey = 'A new value'
state.otherKey = {
propOne: 'val 1',
propTwo: 'val 2'
}
return state
}).commit() // <- persistant state
```
You can make actions (and any) modular easy using spread operator.
```js
const counterActions = {
add () {
this.ss({
count: this.state.count + 1
})
},
sub () {
this.ss({
count: this.state.count - 1
})
}
}
const store = new Wallant({
persistant: true,
state: {
count: 0
},
actions: {
...counterActions,
...otherActions
}
})
```
---
## validate
Wallant provides and easy way to break bad states.
```js
const store = new Wallant({
persistant: true,
state: {
count: 0
},
actions: {
...counterActions
},
validate: {
count (oldValue, newValue) {
return newValue < 20
}
}
})
```
For use, declare on methods with the name of property in state, for example `count`, this method will be used for validate count states in state, if method return false setState will be rejected in `count` key, else will be applied. That easy!
---
## computed
And last, computed properties, this can be your life so easy, first you need declare a new node `computed`.
and declarea a function than use state and return a computed value, for example:
```js
const store = new Wallant({
persistant: true,
state: {
count: 0
},
actions: { ... },
validate: { ... },
// and computed
computed: {
sevenTimesCount () {
return this.state.count * 7
}
}
})
```
`sevenTimesCount` return `count` multiplied seven times, and you can use this in React component as a property.
```js
render () {
return (
<Text>{ store.state.sevenTimesCount }</Text>
)
}
```
Wallant creates a key named as computed funcion, be care, because this values are `undefined` meanwhile store is created, btw, if you are computing for example an array for filter users:
```js
[...]
computed: {
filteredUsers () {
return this.state.users
.filter(user => user.name.startsWith('a'))
.map(({ name }) => name.first + ' ' + name.last)
}
}
[...]
render () {
return (
<View>
{
store.state.filteredUsers.map(i =>
[...]
)
}
</View>
)
}
```
Get an error trying to invoke `.map` of `undefined`. **How to solve this?**
```js
render () {
return (
<View>
{
!!store.state.filteredUsers &&
store.state.filteredUsers.map(i =>
[...]
)
}
</View>
)
}
```
`!!store.state.property &&` avoid render of element bellow meanwhile property in store is `undefined`.
---
### Flow
<p align="center">
<img src="https://i.imgur.com/tkJjZZ6.png" alg="Wallant data flow">
</p>