React Nativeでアプリを開発するときに、デバイスのストレージにデータを保存したいときに、Storeの永続化に使えるredux-persistが便利です。
しかし、さほど複雑なデータを扱わなくとも、Reduxの導入が必須になります。
個人的には、Reduxを導入するには複雑なファイル群がどうしてもハードル高く思ってしまいました。
世界一シンプルなReactNative + Reduxチュートリアル①
この記事を参考して、とってもシンプルにReduxを導入できました。
とっても助かりました。
上記踏まえて、
・ インターフェイス上1Tapで複数のStateを変更するイベント処理をView側の関数に入れて、一旦中継してからStoreへ渡すようにする
・ redux-persistの導入を加える
ことを加味したコードの一部をご紹介します。
事前準備
必要なライブラリをインストール
npm install --save redux react-redux redux-persist react-native-asyncstorage
コード部分
redux部分
actions.js, reducers.js, store.jsを一つのファイルにまとめます
redux-persistを導入し、AsyncStorageに保存します。
redux.js
// redux.js
import { combineReducers, createStore } from 'redux';
import { persistReducer, persistStore } from 'redux-persist';
import { AsyncStorage } from 'react-native';
// actions.js
export const addItem = (inputText1, inputText2) => ({
type: 'ADD_ITEM',
inputText1: inputText1,
inputText2: inputText2
});
export const deleteItem = (targetIndex) => ({
type: 'DELETE_ITEM',
targetIndex: targetIndex
});
const INITIAL_STATE = {
listData: [],
currentIndex: 0,
}
// reducers.js
const reducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'ADD_ITEM':
const newList = {
inputText1: action.inputText1,
inputText2: action.inputText2,
key: state.currentIndex + 1
}
return {
...state,
listData: [...state.listData, newList],
currentIndex: state.currentIndex + 1
}
case 'DELETE_ITEM':
const targetIndex = action.targetIndex + 1;
console.log(targetIndex)
const newlistData = state.listData.filter(function(v){
return v.key != targetIndex;
});
console.log(newlistData)
return {
...state,
listData: newlistData,
}
default:
return state;
}
}
export const reducers = combineReducers({
listData: reducer
})
// store.js
const persistConfig = {
key: 'MAIN',
storage: AsyncStorage,
}
const persistedReducer = persistReducer(persistConfig, reducers)
const store = createStore(persistedReducer)
export const persistor = persistStore(store)
export default store
console.log(store)
スクリーンの部分
一部のStoreには渡さないstateのイベントはここの中で完結します。
Screen.js
import React from 'react';
import { Text, View, ScrollView, FlatList } from 'react-native';
import { Input, Button, ListItem } from 'react-native-elements';
import { connect } from 'react-redux';
import { addItem, deleteItem } from './redux';
import { store } from './redux';
class MainScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
inputText1: "",
imageText2: "",
targetIndex: ""
};
}
addData = () => {
this.props.addItem(this.state.inputText1, this.state.inputText2)
this.setState({inputText: "", imageUrl: ""});
}
deleteData = (item) => {
const targetIndex = item.key - 1;
this.props.deleteItem(targetIndex)
}
render() {
let listContents = this.props.listData;
return (
<React.Fragment>
<ScrollView>
<FlatList data={listContents}
extraData={this.state}
renderItem={({item}) =>
<ListItem key={"listItem_" + item.key} title={item.inputText1 + item.inputText2} onPress={() => this.deleteData(item)} />
}
keyExtractor={(item, index) => "todo_" + item.index}
/>
</ScrollView>
<View>
<Input
onChangeText={(text) => this.setState({inputText1: text})}
value={this.state.inputText1}
keyboardType="default"
returnKeyType="done"
/>
<Input
onChangeText={(text) => this.setState({inputText2: text})}
value={this.state.inputText2}
keyboardType="default"
returnKeyType="done"
/>
<Button title="Add" onPress={this.addData} />
</View>
</React.Fragment>);
}
}
const mapStateToProps = state => ({
listData: state.listData.listData
})
const mapDispatchToProps = {
addItem,
deleteItem
}
export default connect(mapStateToProps, mapDispatchToProps)(Screen)
書き出す部分
必要なものをインポートし、PersistGateを加えます。
App.js
import React from 'react';
import { Provider } from "react-redux";
import store, { persistor } from "./redux";
import { PersistGate } from 'redux-persist/integration/react'
import MainScreen from './Screen';
export default class App extends React.Component {
render () {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<Screen />
</PersistGate>
</Provider>
)
}
}