Realm 的两个特性: 单向数据流和响应式绑定(React Native 版 )

这两个特性也是目前随着前端 UI 越来越复杂,用来解耦的好方法。

单向数据流 Unidirectional data flow

简单来说单向数据流就是确保数据是单向绑定的,例如下图,数据的更新永远是顺着一个方向而不能反过来。

要做到数据的单向流动,需要做到以下两个方面。

数据状态只保存在一处。 Single source of truth

数据状态只保存在一处不用多说了,主要就是数据结构的设计,要避免把一种状态用两种描述放在不同的表里,然后再来同步。这样你再精巧的代码都弥补不了数据结构的缺陷。数据结构比代码重要。

状态的读写操作分开,在状态改变后通知更新 UI。

写操作直接操作数据,不要有中间状态,然后通知数据更新。Realm 是通过 realm.write 来处理所有的写操作。

realm.write(() => {
  let myCar = realm.create('Car', { //创建新的记录
    make: 'Honda',
    model: 'Civic',
    miles: 1000,
  });
  myCar.miles += 20; // 更新
  realm.delete(myCar); //删除
});

如果你在realm.write() 之外试图写操作,就会抛出错误。

在更新后,会有一个 change event

realm.addListener('change', () => {
  //通知更新界面
})

这样读写分开可以降低程序的复杂度,使得逻辑更清晰。至于界面的更新就交给 React 了,配合得正好。

所以其实可以考虑直接使用 Realm 来作为 Flux 架构的 Store,而不用 Redux。(一个猜测

Reactive 响应式编程

Realm 查询的结果是自动更新的。例如

demo

输入姓名后点击 Save,人数就自动更新。在上面例子中,我们只需在 componentWillMount 里查询(绑定)一次返回的 results 值, 此后只要 Person 数目改变,界面里的 results.length 就会改变,而不用再次去查询数据库了。React 会帮助你高效处理界面更新的部分。代码如下

class rmdemo extends Component {
  constructor(props) {
    super(props)
    this.state = {
      inputText: ''
    }
  }
  componentWillMount(){
    this.realm = new Realm({
      schema:[{name:'Person', properties:{name: 'string'}}]
    })
    this.results = this.realm.objects('Person')
    this.realm.addListener('change', () => {
      this.forceUpdate()
    })
  }
  _handleTouch(){
    this.realm.write(()=>{
      this.realm.create('Person', [this.state.inputText]);
    })
  }
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to React Native and Realm!
        </Text>
        <Text style={styles.welcome}>
          Count of Persons in Realm: {this.realm.objects('Person').length}
        </Text>
        <View style={{alignItems: 'center'}}>
          <TextInput
            style={{height: 40, width: 200, borderColor: 'gray', borderWidth: 1}}
            onChangeText={(inputText) => this.setState({inputText})}
            value={this.state.inputText}
          />
          <TouchableWithoutFeedback onPress={this._handleTouch.bind(this)}>
            <View>
              <Text style={{fontSize: 24, color: 'blue'}}>
                Save
              </Text>
            </View>
          </TouchableWithoutFeedback>
        </View>
      </View>
    )
  }
}