Last active
March 10, 2023 21:50
-
-
Save vincicat/1ba1abbbdf4348c3183cf48b90ea0a36 to your computer and use it in GitHub Desktop.
Single-File JavaScript Example: useSWR in React Native
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* eslint-disable react-native/no-inline-styles */ | |
import React, {useEffect, useRef} from 'react'; | |
import {View, Text, AppState, StyleSheet, SafeAreaView} from 'react-native'; | |
import NetInfo from '@react-native-community/netinfo'; | |
import useSWR, {SWRConfig} from 'swr'; | |
import {FlatList} from 'react-native-gesture-handler'; | |
const randomInt = range => Math.floor(Math.random() * range); | |
// https://github.com/vercel/swr/discussions/532 | |
const initFocusOld = revalidate => { | |
let appState = AppState.currentState; | |
const onAppStateChange = nextAppState => { | |
if (appState.match(/inactive|background/) && nextAppState === 'active') { | |
revalidate(); | |
} | |
console.log('state change', nextAppState); | |
appState = nextAppState; | |
}; | |
AppState.addEventListener('change', onAppStateChange); | |
return () => { | |
AppState.removeEventListener('change', onAppStateChange); | |
}; | |
}; | |
// offical. note: callback actually is revalidate | |
const initFocus = callback => { | |
let appState = AppState.currentState; | |
const onAppStateChange = nextAppState => { | |
/* If it's resuming from background or inactive mode to active one */ | |
if (appState.match(/inactive|background/) && nextAppState === 'active') { | |
console.log('<App> refocusing. refreshing.'); | |
callback(); | |
} | |
appState = nextAppState; | |
}; | |
// Subscribe to the app state change events | |
const subscription = AppState.addEventListener('change', onAppStateChange); | |
return () => { | |
subscription.remove(); | |
}; | |
}; | |
// | |
// https://github.com/huozhi/swr-rn-example | |
function Page() { | |
const key1 = 'hello'; | |
const key2 = 'initial'; | |
const key3 = 'change by time'; | |
const key4 = 'change on foreground'; | |
const {data: data1} = useSWR(key1); | |
const {data: data2} = useSWR(key2); | |
const {data: data3, mutate: mutateKeyTimer} = useSWR( | |
key3, | |
() => `${randomInt(200)}`, | |
{ | |
revalidateOnFocus: false, | |
}, | |
); | |
const {data: data4} = useSWR(key4, () => `${randomInt(200)}`); | |
useEffect(() => { | |
const timer = setInterval(() => { | |
mutateKeyTimer(); | |
}, 2000); | |
return () => clearInterval(timer); | |
}, [key3, mutateKeyTimer]); | |
const keyValuePairs = [ | |
['KEY', 'VALUE'], | |
[key1, data1], | |
[key2, data2], | |
[key3, data3], | |
[key4, data4], | |
]; | |
return ( | |
<View style={styles.table}> | |
{keyValuePairs.map(([key, value]) => ( | |
<View key={key} style={styles.row}> | |
<Text style={{fontWeight: 'bold'}}>{key}</Text> | |
<Text>{value}</Text> | |
</View> | |
))} | |
</View> | |
); | |
} | |
// from https://blog.logrocket.com/handling-data-fetching-next-js-useswr/ | |
function UserPage() { | |
const address = 'https://randomuser.me/api/?results=6'; | |
const fetcher = url => fetch(url).then(res => res.json()); | |
const {data, error} = useSWR(address, fetcher); | |
let content; | |
if (error) { | |
content = <Text>Loading failed...</Text>; | |
} | |
if (!data) { | |
content = <Text>Loading...</Text>; | |
} else { | |
console.log('Received', data.length); | |
if (!data.results) { | |
content = <Text>Malformed data: {JSON.stringify(data)}.</Text>; | |
} else { | |
console.log('Received', Object.keys(data)); | |
} | |
} | |
return ( | |
<> | |
{data && data.results ? ( | |
<FlatList | |
data={data.results} | |
keyExtractor={(item, index) => `user-list${index}`} | |
renderItem={({item}) => { | |
return ( | |
<View | |
style={{ | |
padding: 10, | |
borderBottomColor: '#bbb', | |
borderBottomWidth: 1, | |
}}> | |
<Text> | |
{item.name.first} {item.name.last} | |
</Text> | |
<Text>Country: {item.location.country}</Text> | |
<Text>State: {item.location.state}</Text> | |
<Text>Email: {item.email}</Text> | |
<Text>Phone: {item.phone}</Text> | |
<Text>Age: {item.dob.age}</Text> | |
</View> | |
); | |
}} | |
/> | |
) : ( | |
content | |
)} | |
</> | |
); | |
} | |
function AppContainer() { | |
return ( | |
<SafeAreaView> | |
<UserPage /> | |
</SafeAreaView> | |
); | |
} | |
export default function App() { | |
// const prev = useRef(null); | |
return ( | |
<SWRConfig | |
value={{ | |
provider: () => new Map(), | |
isVisible: () => { | |
return true; | |
}, | |
initFocus, | |
initReconnect: revalidate => { | |
let prev = {}; //closureeeeee | |
const unsubscribe = NetInfo.addEventListener(state => { | |
const ts = Date.now(); | |
console.log('[network] prev: ', `--${ts}--`, JSON.stringify(prev)); | |
// replace prev with prev.current if you refer ref version | |
if ( | |
// possible value: null > true or false | |
prev.isInternetReachable === false && | |
state.isConnected && | |
state.isInternetReachable | |
) { | |
console.log('<App> reconnected. refreshing'); | |
revalidate(); | |
} | |
// prev.current = state; | |
prev = state; | |
console.log('[network] curr: ', `--${ts}--`, JSON.stringify(state)); | |
console.log('[network] saved: ', `--${ts}--`, JSON.stringify(prev)); | |
}); | |
return () => { | |
//clean up | |
unsubscribe(); | |
}; | |
}, | |
}}> | |
<AppContainer /> | |
</SWRConfig> | |
); | |
} | |
const styles = StyleSheet.create({ | |
container: { | |
backgroundColor: '#fff', | |
alignItems: 'center', | |
justifyContent: 'center', | |
alignSelf: 'center', | |
flex: 1, | |
}, | |
table: { | |
maxHeight: 120, | |
alignSelf: 'center', | |
alignItems: 'stretch', | |
}, | |
row: { | |
flex: 1, | |
alignSelf: 'stretch', | |
justifyContent: 'space-between', | |
flexDirection: 'row', | |
width: 200, | |
}, | |
cell: { | |
flex: 1, | |
alignSelf: 'stretch', | |
}, | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note: this one is a huge pain for RN (see #417), official doc is unclear (not include an example is okay as RN App is huge, but they don't even give a repo🫠), example are not much (another notable mention), and the library may not be future-proof by some boilerplate author (example: React Native Template New Architecture)
Move to either Apollo (GraphQL API but RESTful can work too) or react-query (RESTful API) will be a better choice 🥲. [link]