LoginSignup
10
7

More than 3 years have passed since last update.

redux-persistを使わずに、ReactNativeのstateを永続化する!

Last updated at Posted at 2019-04-30

alt
ワイ最近、reduxを使うのを止めたんや。
そいで、気づいたんやredux-persistが使えない。
何でや????
yarn add redux-persistしてるんやで。
redux-persistにissue建てな!

仕方がないからバニラreact nativeで、手軽に、stateや、propsを保存する方法を考えたんや!

仕方ないから、redux-persistにプルリクすることにしたんや。

redux-persistと、reduxを使わずに、stateをデータベースに保存するコードをかいたので、マージしてください。」
って。

返信は帰って来なかったやで。
日本語で書いたのが悪かったんやろか?
いや、ワイが日本語読めるんやから、ライブラリ作るくらい優秀な人は、日本語ぐらい読めるはずやで、
何が問題なんやーーー

ちなみに、以下のコードをプルリクしたやで。

componentDidMountで、stateをAsyncStorageから読み込み、
componentDidUpdateで、stateに変化があるたびにAsyncStorageに保存する
単純なコードや。
setStateが発火するたびにasyncStorageにstateを丸ごと保存するやで。
ただ、巨大なjsonを、parseするのは、時間がかかるので小さなstateの時のみ使える方法やで!

import React, { Component } from 'react'
import { StyleSheet, Text, View, AsyncStorage } from 'react-native'

const retrieveData = async str => {
  try {
    const value = await AsyncStorage.getItem(str)
    if (value !== null) {
      return value
    } else {
      return null
    }
  } catch (error) {
    return null
  }
}

const storeData = async (key, value) => {
  try {
    await AsyncStorage.setItem(key, value)
  } catch (error) {

  }
}

export default class App extends Component {
  state = {
    counter: 0
  }

  componentDidMount = () => {
    this.setInitialState()
  }

  setInitialState = async () => {
    const initialState = await retrieveData('App')
    if (initialState) {
      const parsedState = await JSON.parse(initialState)
      this.setState(parsedState)
    }
  }

  componentDidUpdate (prevProps, prevState) {
    if (this.state !== prevState) {
      const stringifiedState = JSON.stringify(this.state)
      storeData('App', stringifiedState)
    }
  }

  increment = () => {
    this.setState({ counter: this.state.counter + 1 })
  }

  render () {
    return (
      <View style={styles.container}>
        <Text onPress={() => this.increment()}>increment</Text>
        <Text>{this.state.counter}</Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
})

小規模なら、案外使える!
でも、ちょっと大きなデータを食わせると目に見えて遅くなる。
なんてこった。facebook! AsyncStorageは粗大ゴミだぞ!

そこで、AsyncStorageの代わりに、react-native-storageを使ったところ全てがうまくいった。
ちょっと大きいデータをセーブしてもロードしても、早い!

だいたい以下のようなコードを、実務でredux-persistの代わりに使っている。

yarn add react-native-storage
import React, { Component } from 'react'
import { StyleSheet, Text, View, AsyncStorage } from 'react-native'
import Storage from 'react-native-storage'

// storageを作成
const storage = new Storage({
  storageBackend: AsyncStorage
})

export default class App extends Component {
  state = {
    counter: 0
  }

  // this.constructor.displayNameで、自身のクラス名を取得
  className = this.constructor.displayName

  componentDidMount = () => {
    this.setInitialState()
  }

  setInitialState = async () => {
    // react-native-storageは、読み込みがとても速い
    storage
      .load({ key: this.className })
      .then(res => this.setState(res))
      .catch(err => console.warn(err))
  }

  componentDidUpdate (prevProps, prevState) {
    if (this.state !== prevState) {
      // stateに変化があったら、this.stateを丸ごと保存する。
      // react-native-storageは速いので、丸ごと保存しても大丈夫
      storage.save({
        key: this.className,
        data: this.state
      })
    }
  }

  increment = () => {
    this.setState({ counter: this.state.counter + 1 })
  }

  render () {
    return (
      <View style={styles.container}>
        <Text onPress={() => this.increment()}>increment</Text>
        <Text>{this.state.counter}</Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
})

あんなに素晴らしいと感じていたreduxが今ではゴミのように思える。
reduxは今でも好きだけど、react-nativeの得意なプロトタイプ制作やスタートアップには適さない

10
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7