如何使用AsyncStorage React Native缓存API数据

Jat*_*eja 4 android caching reactjs react-native redux

React原生及其概念相当新.我已经和RN一起玩了一段时间来创建一个从中获取API数据的应用程序

http://jsonplaceholder.typicode.com/photos

我一直在研究AsyncStorage的文档,以实现我如何缓存API数据,以便在终止应用程序时,它不必一次又一次地处理从web获取数据,但是无法成功实现它.

如果你可以根据它给我提供帮助/建议,那就太好了.我在我的应用程序中包含了2个重要文件的源代码,以及我试图实现的Test.js文件.

import React, {Component} from 'react';
import { FlatList, View, Text, AsyncStorage, ActivityIndicator } from 'react-native';
import axios from 'axios';
import GalleryDetail from './GalleryDetail';

class GalleryList extends Component {

state = { photos: []};

componentDidMount() {
    axios.get('http://jsonplaceholder.typicode.com/photos')
    .then(response => this.setState({ photos: response.data }))
    .catch((error)=> console.warn("fetch Error: ", error));
}

getPhotos = async()=> {
    try {
        photos = await AsyncStorage.getItem('GalleryPhotos');
    }
    catch (error) {
        console.error(error);
    }
}

savePhotos(){
    AsyncStorage.setItem('GalleryPhotos', this.state.photos);
    console.log('works !');
}

renderPhoto = ({item})=> {
    return <GalleryDetail photo={item}/>
}

keyExtractor = (photo, index) => photo.id;

render () {

    if(!this.state.photos){
        return <ActivityIndicator/>;
    }

    return (
            <FlatList
                data = {this.state.photos}
                keyExtractor={this.keyExtractor}
                renderItem={this.renderPhoto}
            />
    );
}
}

export default GalleryList;
Run Code Online (Sandbox Code Playgroud)

和GalleryDetail链接GalleryList-

import React, {Component} from 'react';
import { Text, View, Image } from 'react-native';
 import Card from './Card';
 import CardSection from './CardSection';

const GalleryDetail = (props)=> {
     return (
        <Card>
            <CardSection style = {styles.headerContentStyle}>
                <Image
                    style={styles.thumbnailStyle}
                    source = {{ uri: props.photo.thumbnailUrl}}/>
                <Text style= {styles.textStyle}>{props.photo.title}    </Text>
            </CardSection>
        </Card>
    );
};

const styles = {
   headerContentStyle: {
       flexDirection: 'column',
       justifyContent: 'space-around'
   },

   thumbnailStyle: {
       height: 60,
       width: 60
   },

   textStyle: {
       fontSize: 12,
       //textAlign: 'right',
       flexDirection: 'row',
       justifyContent: 'flex-end',
       flex: 1,
       flexWrap: 'wrap',
       marginLeft: 5,
       marginRight: 5,
    }
    }

    export default GalleryDetail;
Run Code Online (Sandbox Code Playgroud)

我的尝试方法是 - 在启动应用程序时,它将首先查看asyncStorage,如果它找到数据 - 它从异步中获取,否则进入Web,再次获取和存储以供以后使用.我试图在一个单独的文件中实现这样的,因为我想要分解我已经运行的应用程序.奇怪的破解语法是

State = {
        photos: []
    }

    componentDidMount() {

        // just a variable acting to fetch data from the stored keyvalue pair

        check = AsyncStorage.getItem("PhotosKey").then((response) => {
                     this.setState({"PhotosKey": response});
                      }).done();

        if(check) {
            console.log('Data was fetched!!!!!');
            check();
        }

        else {
            console.log("Data was not fetched!");

            var Data = axios.get('http://jsonplaceholder.typicode.com/photos').
            then(response => this.setState({ photos: response.data })).
            catch((error)=> console.warn("fetch Error: ", error));



        }
    }
Run Code Online (Sandbox Code Playgroud)

提前致谢!

Sub*_*thy 8

async componentDidMount() {
    const photoStorage = await AsyncStorage.getItem('GalleryPhotos')
    if(photoStorage) {
      try {
        const photoResp = await axios.get('http://jsonplaceholder.typicode.com/photos')
        const photoData = await JSON.stringify(photoResp.data)
        await AsyncStorage.setItem('GalleryPhotos', photoData);
      } catch(e) {
        console.warn("fetch Error: ", error)
     }
    .then(response => this.setState({ photos: response.data }))
   }
 }
Run Code Online (Sandbox Code Playgroud)

后来

getPhotos = async()=> {
  try {
      photos = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
  }
  catch (error) {
    console.error(error);
  }
}
Run Code Online (Sandbox Code Playgroud)


Rex*_*Low 6

方法Subramanya基本上是您开始所需的全部内容,我将介绍一种状态管理方法,redux-persist当您的应用程序增长时,您绝对可以欣赏到这种方法。

Redux Persist具有高性能、易于实现和易于扩展的特点。

假设您的应用程序连接redux并实现了一个相当有组织的状态树,redux-persist存储整个应用程序状态AsyncStorage您选择的任何存储引擎。

例如,假设您的 API 端点返回一组照片,您需要做的就是更新商店,并且您的用户可以期望他们的数据是安全的并使用redux-persist.

我还没有测试下面的所有代码

让我们定义第store一个,

import { AsyncStorage } from 'react-native';
import { createStore, compose, applyMiddleware, } from "redux";
import { persistStore } from "redux-persist";
import ReduxThunk from "redux-thunk";

import reducers from "../reducers"

const middleWare = [ReduxThunk]

const store = createStore(
  reducers, 
  {},
  compose(applyMiddleware(...middleWare))
)

// you can define more parameters, like blacklist or whitelist a reducer
// also, specify storage engine
persistStore(store, { storage: AsyncStorage });

export default store;
Run Code Online (Sandbox Code Playgroud)

在您的应用程序入口点,

import React, { Component } from "react";
import { Provider } from "react-redux";
import Router from "./Router";
import store from './store';

export default class App extends Component {

  constructor(props) {
    super(props);
  }

  render() {
    return (
      <Provider store={store}>
        <Router />  // navigator
      </Provider>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

最后,您的 API 逻辑。

// action creator
export storePhoto = photos => {
    return {
        type: 'STORE_PHOTOS',
        payload: photos
    }
}

// photos reducer
import { REHYDRATE } from 'redux-persist/constants';

export default (state = {}, action) => {
  switch (action.type) {
    case STORE_PHOTOS:
      return { ...state, photos: action.payload }
  // this is where `redux-persist` handles caching
    case REHYDRATE:
      var incoming = action.payload;
      if(incoming) return { ...state, ...incoming }
      return state;
    default:
      return state;
  }
};
Run Code Online (Sandbox Code Playgroud)

要检索数据,您将看到 redux 抽象掉了所有多余的逻辑,没有更多,setItem, getItem因为redux-persist它已经为您自动执行了。

import { connect } from "react-redux";
import { storePhotos } from "./actions";

class GalleryList extends Component {

    async componentDidMount() {
        const photos = await axios.get('http://jsonplaceholder.typicode.com/photos');
        storePhoto(photos)
    }

    renderPhoto = ({ item }) => <GalleryDetail photo={item}/>

    keyExtractor = (photo, index) => photo.id;

    render () {
        return (
            <FlatList
                data = {this.props.photos}
                keyExtractor={this.keyExtractor}
                renderItem={this.renderPhoto}
            />
        );
    }
}

// pull data from photos reducer
const mapStateToProps = ({ photos }) => {
    return {
        photos: photos.photos
    }
}

export default connect(mapStateToProps, { storePhotos })(GalleryList);
Run Code Online (Sandbox Code Playgroud)

总结一下,

  1. 在您的项目中安装 redux-persist。
  2. 从 redux-persist 中导入 persistStore 和 autoRehydrate 。
  3. 将 autoRehydrate 添加到您的商店。
  4. 将您的商店传递给persistStore。
  5. 聆听您的减速器上的persist/REHYDRATE 操作并相应地填充状态。

希望我的回答有帮助!