Reload data from FlatList - React Native - react-native

I have a FlatList that fetches data from my API, and I want to refresh it everytime my database gets updated. Can someone help me?
My code:
export default class Feed extends Component {
constructor(props) {
super(props);
this.state = {
dataSource: []
};
}
componentDidMount() {
fetch('http://192.168.200.100:3000/posts')
.then(response => response.json())
.then((responseJson) => {
this.setState({
dataSource: responseJson
})
})
.catch(error => console.log(error))
}
render() {
return (
<KeyboardAvoidingView >
<Header>
<FeedModal></FeedModal>
</Header>
<FlatList
keyExtractor={props => props.id}
data={this.state.dataSource}
renderItem={({ item }) => <FeedPosts title={`${item.title}`} photoDesc={`${item.description}`} postImg={`${item.photo}`} ></FeedPosts>}
>
</FlatList>
</KeyboardAvoidingView>
);
}
}

To update the values inside your app when changes happen on it from the backend you will need either a Real Time database or you will have to work with web sockets:
Web Sockets:
WebSocket is an internet communication protocol with a relevant interesting feature: it provides a full-duplex channel over a single TCP connection.
With WebSockets, a client and a server are able to talk to each other in real time, like they're involved in a telephone call: once connected, the client is able to receive data from the server, without any need to continuously refresh the web page. On the other hand the server will also be able to receive data in real time from the client inside the same connection. for react native check this article about websockets ,it should be handled from backend too.
Realtime Database:
Real-time database contains the data which is been processing in real-time. It uses the real-time processing techniques to handle the workloads.
for example firebase realtime-database.

Related

How to use useEffect() without performance degradation

I have a React Native app where, on one screen, I have a useEffect hook that constantly fetches data from a site and updates my local variable with that data (see below for a simplified example). The problem I am running into though is that this is killing the performance of my app. Even if you leave this screen, the app is sluggish.
The issue is no doubt caused by the countless calls to the URL to get the data & constantly resetting my local variable with the data. I tried using a dependency array with the hook, but if I do that it doesn't continually update, it only updates on the first load of the screen and I need it to update whenever there is a change (whenever new data is available).
Is there a way to do this so that I constantly get any updates from the remote source but don't slow down my app?
const [retrievedData, setRetrievedData] = [{}];
useEffect(() => {
let fetchedData;
fetch(
'https://site-with-data.com',
)
.then(response => response.json())
.then(json => {
setRetrievedData(processData(json.events));
})
.catch(error => console.error(error));
});
When useEffect doesn't have a dependencies array (the second argument), it will run on every render. That is why you are making so many calls.
If you need to update the data real-time, the first question you must answer is: how will the client know the data has changed in the server?
One way you could make the server notify the client is by using WebSockets. A WebSocket creates a bidirectional connection between the client and the server, and the server can notify the client whenever anything changes. Other than that, you could also use a technique called "long polling" or "server-sent events".
But any of these three solutions would require you to change your server (in addition to your client).
Quick fix: limit the update frequency to "refresh every N seconds"
The quick and dirty alternative without changing the server is just to decide a frequency (e.g., update every 5s) and go with it in the client.
Example:
useEffect(() => {
const intervalId = setInterval(() => {
fetch(
'https://site-with-data.com',
)
.then(response => response.json())
.then(json => {
setRetrievedData(processData(json.events));
})
.catch(error => console.error(error));
}, 5000); // update every 5s
return () => clearInterval(intervalId);
}, []); // add to this array any variable that affects the fetch (e.g., URL)
Which number of seconds should you use? That will depend on each case. To decide that, evaluate both UX and server load.

Nuxtjs Redis cache implementation for API calls inside components

I am using the plugin Nuxt Perfect Cache to server-side cache my QPI requests to an external service.
I am using the cacheFetch method on Component level and this component is loaded on a dynamic page (defined by its slug). When I navigate to the dynamic page, the API call is not cached in Redis, however when I reload the page, the caching happens as expected.
Below is how my code is structured:
_slug.js (for /users)
<template>
<h1>{{ user.name }}</h1>
<Posts :author = user.id>
</template>
<script>
import Posts from '~/components/Posts.vue'
export default {
components: { Posts },
async asyncData({params}) {
const user = await fetch(`/users/${params.slug}`)
.then(res => res.json())
}
}
</script>
And inside Posts.vue I use the perfect cache cacheFetch method to fetch the list of posts, something like:
props: ['author'],
async fetch() {
this.posts = await this.$cacheFetch({ key:`user--#{this.author}--posts`, expire: 60 * 60 },
async () => {
return await fetch(`/users/#{this.author}/posts`).then(res => res.json())
})
},
data() {
return {
posts: []
}
}
When I load the user page directly in the browser, the json response for the posts is saved in Redis as expected. When I navigate from within the application using a NuxtLink, the user page is displayed correctly (including the posts), but no key is set or get from Redis.
How can I ensure the API calls are cached when users interact with the app?
redis is only available in server side not client side when you are navigating in client side you don't have access to redis you can set absolute link to render server side when user is navigating but I don't recommend this.
the best solution is cache data in redis in your api.

What is the best practice to avoid establishing cumulative/multiple socket connections from a react native Component

I am working on a React Native mobile chat application utilizing laravel-echo library for socket connections.
I have a function based EchoServer component, rendered from a custom header component on every page. It calls handleNewMessage through useEffect hook and sets a new Echo object for listening to sockets.
let echo = new Echo({
broadcaster: 'socket.io',
client: socketio,
authEndpoint: constants.echoServer + '/broadcasting/auth',
host: constants.echoServer + ':' + constants.echoServerPort,
auth: {
headers: {
Accept: "application/json",
Authorization: `Bearer ${params.access_token}`,
}
},
});
echo
.private(channel)
.notification((notification) => {
handleNewMessage(notification);
});
console.log('Join "online" channel');
echo.join('online')
.here(users => {
if(users.find(data => data.id === params.user.id)) {
setState({
icon: ICONS.online,
color: COLORS.online
});
}
});
echo.connector.socket.on('subscription_error', (channel, data) => {
console.log('channel subscription error: ' + channel, data);
});
I do not have any issues with listening notifications from the socket connection. However, since this component is rendered in a header component as mentioned above, it also creates a new connection every time the header is rendered. That causes same notifications to come multiple times increasingly (At first I receive 1 notification, then 2 and 3 etc.)
I solved that problem by using a useContext hook for the echo object. I basically used the useContext hook as a global variable.
After,
const [ socket, setSocket ] = useContext(SocketContext);
I check if socket already has a value or not, before creating a "new Echo" object.
if (socket){
return;
}
However, with this solution I had to add another context in my parent App.js file such that:
<AuthContext.Provider value={authContext}>
<SocketContext.Provider value={[socket, setSocket]}>
<MessageStore>
<NavigationContainer>
{ user.access_token?
<MenuStack/>
:
<AuthStack/>
}
</NavigationContainer>
</MessageStore>
</SocketContext.Provider>
</AuthContext.Provider>
I can see that nested contexts might be an issue in future (if they're not already) as I already have 3. What I'd like to ask is, is there a better solution in order to check if socket connection has been established without using useContext hook?
I was also thinking maybe useContext is not the best solution for this.
Also establishing the socket connection right after the authentication process only once might be a better solution, instead of checking it every time in the header.
I am looking for suggestions about the best practices for this case.
Thank you for your helps in advance.

show error in react native when internet connection isn't good

I'am doing the last modification on my react native application.
Well, the problem that I get is that when I enter my informations to connect, I'm showin a small boxDialog to say that the verification of your data is working (this time is for comparing information that user entered and sql server data) so when it's correct I'm accessing to home page.
My problem is sometimes, the internet isn't that good so I need that when verification take longer time to show an error saying "please verify your internet connection"
I don't know if there is a method or specific function!!
constructor(props){
super(props);
this.state={
isModalVisible:false,
}}
openModal = () =>{
this.setState({
isModalVisible:true
}) }
userRegister = () =>{
this.openModal();
fetch('http://192.168.1.7:80/recup.php',{
method:'post',
header:{
'Accept':'application/json',
'Content-type' :'application/json'
},
body:JSON.stringify({email:usermail,password:password,})})
.then((responseData)=>responseData.text())
.then((responseJson)=>{
if(responseJson =='Data Matched'){
this.props.navigation.navigate( 'Welcome')}
else{
alert("Merci de saisir vos données correctement")}
})
.catch((error)=>{console.error(error);})
}
render() {
if(!this.state.isLoading){
return(
....
<TouchableOpacity style={styles.butt} onPress={this.userRegister}>
<Text>Connection</Text</TouchableOpacity>
....
If you want to access this (I mean if you want to fetch) url http://192.168.1.7:80/recup.php you should have proper internet connection.
You can handle this with this react-native-netinfo library. https://github.com/react-native-community/react-native-netinfo

React Native: Refresh component on click button

I tried to create a chat in my application. Messages are stored in a server and I comunicate with it with an API. I tried to make it real time chat so I used componentDidUpdate shouldComponentUpdate method (componentDidUpdate and componentwillupdate too) but there is a warning that appears telling me that make my application very weak... in any case I can't do it like this.
I want suggestions to be able to display the message when the user click on the send button and how can I have a notification of receipt of new messages
in case your server is not sending notifications on new message, you can implement polling mechanism to check server for any new message after certain small time intervals.
as long as you are fetching new messages and populating them, using redux, you will only need componentwillreceiveprops method which you can use to set state of new message array.
The warning is probably coming from the "unsafe" (deprecated in React 17) method componentwillupdate. These methods (including componentwillreceiveprops as Firdous mentioned) shouldn't be used anymore in preference for methods such as componentdidupdate.
What you're looking to achieve can be done with an appropriate use of componentdidupdate and perhaps getderivedstatefromprops if needed. For instance, if you have connected your chat view (and your message text input) to redux (which should hold the messages) the componentdidupdate method will listen to incoming prop changes (from the onPress event for instance from your text input) and can therefore update the view with the new props (messages).
I provide some code to more details:
componentDidUpdate(prevProps, prevState) {
if (prevState.msg !== this.state.msg) {
this.getMsgFromApi(this.state.userId).then(data => {
this.setState({ msg: data})
});
}
};
and to display messages when component will mount i do this:
componentWillMount() {
AsyncStorage.getItem(USERID_STORED)
.then(userIdStore => {
this.setState({ userId: userIdStore});
this.getMsgFromApi(this.state.userId).then(data => {
this.setState({ msg: data})
});
});
};
all message are dislaied in a flatlist
<View style={Styles.messagesContainer}>
<FlatList
style={Styles.flatlist}
data={this.state.msg.Conversation}
keyExtractor={(item) => item.datetime.toString()}
renderItem={({item}) => <MsgR msg={item}/>}
inverted= {-1}
/>
</View>
and I do a condition to differentiate if it is a user message or a received message because the API that handles the messages puts them like this :
"Conversation": [
{
"adherent": "received message",
"user": null,
"datetime":"2019-07-09
09: 42: 55"
},
{
"adherent":null,
"user":"user message",
"datetime":"2019-07-04 06: 14: 18"
}
2","user":null,"datetime":"2019-07-03 12: 34: 10"
},
]
display of messages according to the sender:
const msg = this.props.msg;
return (
<View style={[Styles.container, msg.user===null ? Styles.right : Styles.left]}>
<Text style={msg.user===null ? Styles.textMsgRight : Styles.textMsgLeft}>{msg.user===null ? msg.adherent : msg.user}</Text>
</View>
);
I found the solution by adding extraData flatlist prop:
<FlatList
style={Styles.flatlist}
data={this.state.msg.Conversation}
keyExtractor={(item) => item.datetime.toString()}
extraData={this.state} //this prop
renderItem={({item}) => <MsgR msg={item}/>}
inverted= {-1}
/>
and when I click the send button, I re-call getMsgFromApi() method:
onPressSend() {
AsyncStorage.getItem(USERID_STORED)
.then(userIdStore => {
this.setState({ userId: userIdStore});
this.sendMsgS(this.state.userId).then(() => {
this.setState({msgS: ''});
this method --> this.getMsgFromApi(this.state.userId).then(data => {
this.setState({ msg: data,});
});
});
});
}
and it's work fine: when I click on send button, I have the message sent displayed after a few ms, it's unpleasant but it works !