Persistant, auto-validate, and predictable state container for React Native
Lee la documentación en español
npm i -s wallant
basic configuration in /ReactNativeApp/src/Store.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
// 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...
[ DEPRECATED in 2.0 ] This feature save state automatically and allow restore it when app starts, you only need declare
persistant
astrue
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.
// 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.
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 allow you modify state, this
make reference to store
.
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
// 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.
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
}
})
Wallant provides and easy way to break bad states.
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!
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:
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.
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:
[...]
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?
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
.