Skip to content

Latest commit

 

History

History
303 lines (244 loc) · 5.86 KB

README.md

File metadata and controls

303 lines (244 loc) · 5.86 KB

Persistant, auto-validate, and predictable state container for React Native


Lee la documentación en español


install

npm i -s wallant

use

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...

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.

// 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

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
  }
})

validate

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!


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:

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.


Flow