Help us understand the problem. What is going on with this article?

react-nativeでstorageを使おうとすると、cosole.errorが出てしまう

はじめに

スクリーンショット 2019-09-03 10.20.23.png
ReactNative+Exoiで始めるスマホアプリ開発

この本の第7章、React Nativeの状態管理のなかでデータの永続性(保存)
に触れられた部分で、エラーが出てしまい、先に進めなくなってしまった。
そこで、これの解決策を示すことで、後からこの学習に取り組む若者たちの手助けとなるような記事を書いていきたい

 作りたいアプリ

単純なTodoアプリで
検索フィールド、スクロールフィールド、入力フォームがあるアプリ、図にするとこんな感じ↓
IMG_3007.JPEG

コード

App.js
import {createStore} from 'redux'
import {persistReducer,persistStore} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import rootReducer from './rootReducer'


const persistConfig ={
    key: 'TODO',
    storage,
    whitelist:['todos'.currentIndex]
}
const persistedReducer = persistReducer(persistConfig,rootReducer)
const store = createStore(persistedReducer)


export const persistor = persistStore(store)
export default store
src/actionCreator.js
import {TODO} from './actions'
export const addTodo = (text) =>{
    return {
        type:TODO.ADD,
        text,
    }
}
export const toggleTodo = (todo) => {
    return {
        type:TODO.TOGGLE,
        todo
    }
}
src/action.js
export const TODO ={
    Add:'TODO_APP',
    TOGGLE:'TODO_TOGGLE',
}
src/rootReducer.js
import { combineReducers} from 'redux'
import todoReducer from './todoReducer'

export default combineReducers({
    todos:todoReducer
})
src/store.js
import {createStore} from 'redux'
import {persistReducer,persistStore} from 'redux-persist'
import storage from 'redux-persist/lib/storage'
import rootReducer from './rootReducer'


const persistConfig ={
    key: 'TODO',
    storage,
    whitelist:['todos'.currentIndex]
}
const persistedReducer = persistReducer(persistConfig,rootReducer)
const store = createStore(persistedReducer)


export const persistor = persistStore(store)
export default store
src/todoReducer.js
import {TODO} from './actions'

const initialState = {
  todos:[],
  currentIndex:0,
  }

  const todos = (state = initialState,action) =>{
    switch(action.type){
      case TODO.ADD:
        const newTodo = {title:action.text,index:state.currentIndex,done:false}
        return {
          ...state,
          todos:[...state.todos,newTodo],
          currentIndex:state.currentIndex + 1
        }
        case TODO.TOGGLE:
          const todoItem = action.todo
          const todos = Object.assign([],state.todos)
          const index = todos.indexOf(todoItem)
          todoItem.done = !todoItem.done
          todos[index] = todoItem
          return {
            ...state,
            todos:todos
          }
        default:
          return state
    }
  }
  export default todos
src/TodoScreen.js
import React from 'react';
import { 
  StyleSheet, 
  Text, 
  View,
  StatusBar, 
  Platform, 
  ScrollView,
  FlatList,
  KeyboardAvoidingView,
  AsyncStrage,
  TouchableOpacity,
} from 'react-native';

import {
  SearchBar,
  Input,
  Button,
  ListItem,
} from 'react-native-elements';

import Icon from 'react-native-vector-icons/Feather';
import Icon2 from 'react-native-vector-icons/MaterialIcons';

import {ifIphoneX,getStatisBarHeight, getStatusBarHeight} from 'react-native-iphone-x-helper';

import {connect} from 'react-redux'
import {addTodo,ToggleTodo, toggleTodo} from './actionCreators'
const TODO = "@todoapp.todo"

// iPhoneX対応
const STATUSBAR_HEIGHT = getStatusBarHeight()

const TodoItem =(props) =>{
  // let textStyle = styles.todoItem
  // if(props.done === true){
  //   textStyle = styles.todoItemDone
  // }
  let icon = null
  if ( props.done == true){
    icon = <Icon2 name="done" />
  }
  return (
    <TouchableOpacity onPress={props.onTapTodoItem}>
      {/* <Text style={textStyle}>{props.title}</Text> */}
      <ListItem
        title={props.title}
        rightIcon={icon}
        bottomDivider
        />
    </TouchableOpacity>
  )
}
class TodoScreen  extends React.Component {

  constructor(props){
    super(props);
    this.state = {
      inputText:"",
      filterText:"",
    }
  }
  onAddItem = () => {
    const title = this.state.inputText
    if(title == "" ){
      return
    }
    this.props.addTodo(title)
    this.setState({
      inputTexxt:""
    })
  }

  onTapTodoItem= (todoItem)=>{
    this.props.ToggleTodo(todoItem)
  }
  render() {
    const filterText = this.state.filterText
    let todo = this.props.todo
    if(filterText !== ""){
      todo = todo.filter(t=>t.title.includes(filterText))
    }

    const platform = Platform.os == 'ios' ? 'ios' : 'android'

    return (
      <KeyboardAvoidingView style={styles.container} behavior="padding">
        <SearchBar
          platform={platform}
          cancelButtontTitle='Cancel'
          onChangeText = {(text) => this.setState({filterText: text})}
          onClear={()=>this.setState({filterText:''})}
          value={this.state.filterText}
          placeholder='Type filter text'
          />
        <ScrollView style={styles.todolist}>
          <FlatList data={todo}
            extraData={this.state}
            renderItem={({item}) => 
              <TodoItem
                title={item.title}
                done={item.done}
                onTapTodoItem={()=>this.onTapTodoItem(item)}
                />
            }
            keyExtractor={(item, index) => "todo_" + item.index} 
          />
        </ScrollView>
        <View style={styles.input}>
          <Input
            onChangeText={(text) => this.setState({inputText:text})}
            value={this.state.inputText}
            style={styles.inputText}
          />
          <Button
            icon={
              <Icon
                name='plus'
                size={30}
                color="white"
              />
            }
            onPress={this.onAddItem}
            title=""
            buttonStyle={styles.inputButton}
          />
        </View>
      </KeyboardAvoidingView>
    );
  }
}
const mapStateToProps = state =>{
  return {
    todo:state.todos.todos,
  }
}

const mapDispatchToProps = dispatch =>{
  return {
    addTodo(text){
      dispatch(addTodo(text))
    },
    ToggleTodo(todo){
      dispatch(toggleTodo(todo))
    }
  }
}
export default connect(mapStateToProps,mapDispatchToProps)(TodoScreen)
const styles = StyleSheet.create({
  input:{
    ...ifIphoneX({
      paddingBottom:30,
      height:80
    },{
      height:50,
      }),
      height:70,
      flexDirection:'row',
      paddingRight:10,

  },
  inputText:{
    paddingLeft:10,
    paddingRight:10,
    flex:1,
  },
  inputButton:{
    width:48,
    height:48,
    borderWidth:0,
    borderColor:'transparent',
    borderRadius:48,
    backgroundColor:'#ff6347',
  },
  container:{
    flex:1,
    backgroundColor:'#fff',
    paddingTop:STATUSBAR_HEIGHT ,
  },
  // 追加したUIのスタイル
  filter:{![スクリーンショット 2019-09-03 10.42.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/343721/7a70e98c-3bee-3fda-7fac-17e00d609c09.png)

    height:30,
  },
  inputText:{
    flex:1,
  },

  todoItem:{
    fontSize:20,
    backgroundColor:"white"
  },
  todoItemDone:{
    fontSize:20,
    backgroundColor:"tomato"
  },
});

出てきたエラー

スクリーンショット 2019-09-03 10.42.42.png

よく見てみると
App.js:4
store.js:3とある。

それぞれ該当箇所を抜き出してみると

App.js
{/*4行目*/}
import store,{persistor} from "./src/store"
store.js
{/*3行目*/}
import storage from 'redux-persist/lib/storage'

どうやら、redux-persistを使うところでエラーが出ている模様。

なので。
redux-persistを追加する

npm install redux-persist --save

した後、プロジェクトを立ち上げ、エミュレータを起動してみると
スクリーンショット 2019-09-03 10.54.58.png

結果かわらず😞

いろいろ調べてみると、どうもコマンドが悪かったようで、
https://github.com/irisAsh/learnreactlibrary/wiki/redux_persist
を参考に

yarn add redux-persist

でやってみると
スクリーンショット 2019-09-03 10.58.40.png

エラーが変わった☺️

もう一回

yarn add redux-persist

をやってみると、アプリが表示できた。
スクリーンショット 2019-09-03 11.11.52.png

ただ、下の入力フィールドにテキスト入力後、保存ボタン(右のオレンジ)を押すと
またしてもエラーが
スクリーンショット 2019-09-03 11.10.58.png

ここで、全てのコードを見直してみたところ、以下の間違いに気づいた

src/TodoScreen.js
inputTexxt → inputText
ToggleTodo   toggleTodo
props.todo → props.todos
src/store.js
.currentIndex → ,'currentIndex'
src/action.js
Add → ADD

これを直してプロジェクトを再度立ち上げてみると、エラーが出なくなった。

最初の
スクリーンショット 2019-09-03 10.42.42.png

は出るが、これはDismissで抜けられることが判明したので、解決ということにしておく

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした