Assez nouveau pour React native et ses concepts. Je joue avec RN depuis un certain temps pour créer une application pour récupérer des données API à partir de
http://jsonplaceholder.typicode.com/photos
J'ai cherché dans la documentation d'AsyncStorage pour implémenter comment je peux mettre en cache les données de l'API afin qu'à la fin de l'application, il n'ait pas à se soucier de récupérer les données du Web encore et encore, mais n'a pas réussi à implémenter il.
Ce sera génial si vous pouvez me fournir une aide/suggestion basée sur cela. J'ai inclus mon code source pour les 2 fichiers importants dans mon application, ainsi que le fichier a Test.js avec la façon dont j'essayais d'atteindre.
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;
et GalleryDetail liés à 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;
Ma méthode d'essayer était la suivante: lors du lancement de l'application, il recherchera d'abord dans asyncStorage, s'il trouve les données qu'il récupère depuis async, sinon il va sur le Web, récupérant et stockant à nouveau pour une utilisation ultérieure. J'ai essayé d'implémenter un peu comme ça dans un fichier séparé car je ne voulais pas casser mon application déjà en cours d'exécution. La syntaxe cassée bizarre est
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));
}
}
Merci d'avance!
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 }))
}
}
plus tard
getPhotos = async()=> {
try {
photos = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
}
catch (error) {
console.error(error);
}
}
L'approche de Subramanya
est fondamentalement tout ce dont vous avez besoin pour commencer, je vais juste introduire une approche de gestion d'état avec redux-persist
où vous pourrez certainement apprécier le développement de votre application.
Redux Persist est performant, facile à implémenter et facile à étendre.
Supposons que votre application soit connectée à redux
et qu'elle ait implémenté une arborescence d'état assez organisée, redux-persist
stocke l'intégralité de l'état de l'application avec AsyncStorage
ou tout autre moteur de stockage de votre choix.
Par exemple, supposons que votre point de terminaison API renvoie une collection de photos, tout ce que vous avez à faire est de mettre à jour le magasin et vos utilisateurs peuvent s'attendre à ce que leurs données soient sécurisées et enregistrées avec redux-persist
.
Je n'ai pas testé tout le code ci-dessous
Définissons d'abord le 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;
Au point d'entrée de votre application,
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>
);
}
}
Enfin, votre logique 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;
}
};
Pour récupérer des données, vous verrez que redux résume toutes les logiques excédentaires et il n'y a plus de setItem, getItem
car redux-persist
le fait automatiquement pour votre déjà.
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);
Pour résumer,
J'espère que ma réponse vous aidera!