im looking for a bit of guideness here, im working on a RN app with redux and everytime i enter a new screen on the app, must likely i have a "callinitialData" function inside my useEffect(), using axios to fetch api data to be dispatch() to the redux state.
Everything works but whenever i jump from screen to screen to fast, sometimes i get a 429 error of to many request, so i just setup the redux-persist hoping that would help reduce the amount of request,in my mind thinking that if my api data is equal to my local data, that request wouldnt be necessary to be made.
However it stays the same so i was thinking what would be the best aproach here, on login try to fetch all the data at once > store it at asyncstorage and redux, and fetch that on each screen ?
how would i be able then, if i fetch all the data on login, receive the new data sets from the api in real time?
App functionality -
Edit Profile (img, pass, email, name)
Data Forms (requeast X, submit data, edit forms)
Chat by contacts / create Group chat
Code Example
const ChatScreen = ({ auth: { user }, getChatContacts, chat: { contacts }, navigation }) => {
useEffect(() => {
getChatContacts();
}, []);
const onChatUser = async (_id, name, roomID) => {
console.log(_id, name, roomID, contacts.payload.clone)
navigation.navigate( "Message", {
_id, name, chatRoomId: roomID, allUsers: contacts.payload.clone
});
}
const renderItem = ({ item , index } ) => {
let userName = "";
item.users.map((users, index) => {
let idToCheck = users.toString() !== user._id.toString() ? users : false;
if (idToCheck) {
let getOneUser = contacts.payload.clone.find(x => x._id === idToCheck);
userName += "" + getOneUser.name + ", ";
}
})
return (<TouchableOpacity key={item._id} onPress={() => onChatUser(item._id, item.name, item.roomID)}>
<View style={styles.chatContainer}>
<FontAwesome name="user-circle-o" size={50} color="#000000"/>
<Text style={styles.chatTitle}>{ ((userName).length > 32) ?
(((userName).substring(0,32-3)) + '...') :
userName }</Text>
<FontAwesome name="angle-right" size={25} color="#000000"/>
</View>
</TouchableOpacity>)
};
return (
<SafeAreaView style={styles.container}>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
placeholder="Search friend"
style={styles.chatsearch}
/>
{contacts ?
(<FlatList
data={contacts.payload.allContact}
renderItem={(item, index) => renderItem(item, index)}
keyExtractor={item => item.id}
style={styles.FlatListContainer}
/>) : (<Text style={styles.FlatListContainer}></Text>)
}
</SafeAreaView>
);
}
const styles = StyleSheet.create({});
ChatScreen.propTypes = {
isAuthenticated: PropTypes.bool,
auth: PropTypes.object,
};
const mapStateProps = state => ({
auth: state.auth,
chat: state.chat
});
export default connect(mapStateProps, {getChatContacts} )(ChatScreen);
Redux Action
export const getChatContacts = () => async dispatch => {
const config = {
header: {
"Content-Type": "application/json"
}
}
try {
const res = await axios.get(API_LINK +"/users/getChatContacts",);
dispatch({
type: GET_CONTACT_CHAT,
payload: res.data
});
} catch (err){
console.log(err)
dispatch({
type: ERROR_FAMILY_PARENT,
payload: { msg: err.response, status: err.response}
});
}
};
Related
function ManageData({props, navigation}) {
const [details, setDetails] = useState({
dataList: [],
loading: true,
offset: 1,
totalRecords: 0,
search: '',
});
useEffect(() => {
getData();
}, []);
const getData = async () => {
try {
// console.log('search',details.search);
var params = {};
params = {
'pagination[page]': details.offset,
'pagination[perpage]': 10,
};
if(details?.search?.length > 0){
params['query[search]'] = details?.search;
params['pagination[pages]'] = 30;
params['pagination[total]'] = 293;
}else{
params['query'] = ""
}
const result = await getPayeeDetails(session, params);
// console.log('result',result?.data?.data?.length);
if (result?.data?.data?.length > 0) {
setDetails(prev => ({
...prev,
offset: prev.offset + 1,
dataList: [...prev.dataList, ...result.data.data],
loading: false,
totalRecords: result.data.recordsFiltered,
}));
}
} catch (error) {
console.log('getPayeesError', error);
}
};
const loadMore = () => {
try {
if (details.dataList.length != details.totalRecords) {
setDetails(prev => ({
...prev,
loading: true,
}));
getData();
}
} catch (error) {
console.log('LoadMoreError', error);
}
};
const searchHandler=(data)=>{
try{
console.log('clearData',data);
setDetails(prev => ({
...prev,
dataList:[],
offset:1,
search: data == 'RESET'?"":data,
}));
getData();
}catch(error){
console.log("SearchError",error)
}
}
return (
<BackDropContainer
searchHandler={searchHandler}>
<View style={{backgroundColor: 'white', flex: 1}}>
<FlatList
style={{marginTop: '4%'}}
data={details?.dataList}
renderItem={({item}) => (
<TouchableOpacity onPress={() => showDialog(item)}>
<Item data={item} />
</TouchableOpacity>
)}
onEndReached={loadMore}
keyExtractor={(item, index) => index}
/>
</View>
</BackDropContainer>
);
}
I have a flatlist with searchview in my React Native application. Each time user scrolls to the end of flatlist the loadmore function will be called and also the offset value is increased as 1 to fetch next page from API.
Every time the API results array of 10 data from API so the flatlist will be loaded 10 by 10 for each scroll. When I type some data in searchview the searchHandler function will be called, and there I want to reset the offset as 1 and also need to send typed data to the API.
The issue is searched data and offset is not sending with API whenever I try to search the data. State is not updating properly when searching data.
Note: The data which is types has to be sent along with API whenever user search something.
I'm new to react native, so I apologize for errors in the code. First: I use Android Studio, VS Code, react native(expo) and sqlite(expo), supporting only android (I haven't programmed for ios yet).
I have a serious problem in my code and I have no idea how to start. The 'useEffect', to work, you have to save the file 2 times (ctrl+s in vs code). Don't just open the app.
THIS IS MY LOGIN PAGE login.js
import React, {useState,useEffect} from 'react';
import {View,Text,Pressable,Image,FlatList,ImageBackground,Alert} from 'react-native';
import {TextInput} from 'react-native-gesture-handler';
import fundoLogin from './styleLogin';
import Tb_user from '../../src/models/tb_user';
import Tb_veic_user from '../../src/models/tb_veic_user';
import db from "../../src/services/SQLiteDatabse";
import NetInfo from '#react-native-community/netinfo';
const printUser = (user) => {
console.log(`ID_user:${user.ID_user}, username:${user.username}, senha:${user.senha}, ID_empresa:${user.ID_empresa}, nome_empresa:${user.nome_empresa}, status_user:${user.status_user}`)
}
const printV = (v) => {
console.log(`ID_veic_uso:${v.ID_veic_uso}, username:${v.username}, placa:${v.placa}, atividade:${v.atividade}, data_inic:${v.data_inic}, km_inic:${v.km_inic}, data_final:${v.data_final}, km_final:${v.km_final}, obs:${v.obs}, integrado:${v.integrado}`)
}
function Login({ navigation, route }) {
const [username, setUsername] = useState("")
const [password, setPassword] = useState("")
const [errorLogin, setErrorLogin] = useState("")
const [users, setUsers] = useState([])
const [net, setNet] = useState("")
const [dadosVeic, setDadosVeic] = useState([])
const [info, setInfo] = useState([])
const findTbVeic = (id) => {
return new Promise((resolve, reject) => {
db.transaction((tx) => {
tx.executeSql(
"SELECT * FROM tb_veic_user WHERE integrado=0 AND km_final IS NOT NULL ;",
[],
//-----------------------
(_, { rows }) => {
if (rows.length > 0) {
resolve(rows._array)
}
else {
reject("Obj not found: id=" + id);
} // nenhum registro encontrado
},
(_, error) => reject(error) // erro interno em tx.executeSql
);
});
});
};
useEffect(() => {
NetInfo.fetch().then(state => {
setNet(state.isConnected)
});
if (net === true) {
findTbVeic()
.then(a => setDadosVeic(a))
.then( dadosVeic.map(item => {
// ENVIA DADOS PARA A API
fetch('url API', {
method: 'POST',
body: JSON.stringify({
username: item.username,
placa: item.placa,
atividade: item.atividade,
data_inic: item.data_inic,
km_inic: item.km_inic,
data_final: item.data_final,
km_final: item.km_final
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
//ALTERA O 'INTEGRADO' == 1
Tb_veic_user.updateV( item.ID_veic_uso )
}))
}else{
console.log('sem conexao com a internet')
}
},[])
const importTbUser = () => {
// DADOS DA API SALVA EM CONST USERS
fetch('url API')
.then( res => res.json())
.then(
(dado) => {
setUsers(dado.data)
}
)
// INSERE, NO BANCO DE DADOS, OS DADOS DA API
const a = users.map((element) => {
Tb_user.create({ID_user:element.ID_user, username:element.username, senha:element.senha, ID_empresa:element.ID_empresa, nome_empresa:element.nome_empresa, status_user:element.status_user})
});
}
const login = () => {
// FAZER LOGIN
return new Promise((resolve, reject) => {
db.transaction(tx => {
tx.executeSql(
'SELECT ID_user, username, senha FROM tb_user WHERE username = ? and senha = ? LIMIT 1;',
[username, password],
//-----------------------
(_, { rows }) => {
if (rows.length > 0){
resolve(rows._array),
navigation.navigate('Veic', {
paramKey: username,
})
}else{
reject("Obj not found");
} // nenhum registro encontrado
},
(_, error) => reject(error) // Success
);
});
});
}
return (
<View style={fundoLogin.container}>
<ImageBackground
source={require('../../imagens/1.jpg')}
style={fundoLogin.imageFundo}
>
<Image
style={fundoLogin.imageLogo}
source={require('../../imagens/logo_cymi.png')}
/>
{net === true ?
<Image
style={{height:30,width:30}}
source={require('../../imagens/signal.png')}
/>
:
<Image
style={{height:30,width:30}}
source={require('../../imagens/no-signal.png')}
/>
}
<TextInput
style={fundoLogin.input}
placeholder='Digite seu email'
onChangeText={txtUsername => setUsername(txtUsername)}
value={username}
/>
<TextInput
style={fundoLogin.input}
placeholder='Digite sua senha'
secureTextEntry={true}
onChangeText={txtPassword => setPassword(txtPassword)}
value={password}
/>
{errorLogin === true
?
<View>
<Text style={fundoLogin.error}>email ou senha inválido</Text>
</View>
:
<View>
</View>
}
{(username === "" || password === "")
?
<Pressable
disabled={true}
style={fundoLogin.button}
>
<Text style={fundoLogin.textButton}>Login</Text>
</Pressable>
:
<Pressable
style={fundoLogin.button}
onPress={login}
>
<Text style={fundoLogin.textButton}>Login</Text>
</Pressable>
}
<Pressable
style={fundoLogin.button}
onPress={importTbUser}
>
<Text style={fundoLogin.textButton}>Importar</Text>
</Pressable>
<Pressable
style={fundoLogin.info}
onPress={navigation.navigate('Info')}
>
<Text style={fundoLogin.textInfo}>?</Text>
</Pressable>
</ImageBackground>
</View>
);
}
export default Login;
the app, when opened, will search (if it has internet) in the database for vehicles that have a final kilometer (which have already been selected and released), and will add this information inside the api, updating the database (changing the ' integrated to 1', that is, informing that aql "file" has already been to api)
My app works like this: it starts on the login page (where there is a login button, import button and a company information button) and goes to another page to select a vehicle (this 'veic' page also has the same problem in useEffect). All components are working perfectly fine, I've checked all possible console.logs, and it's running fine. The only problem is that use effect doesn't work (on this page it has to be run 2x to refresh, on the 'veic' page it only does one thing, and the others don't). If anyone can tell me more, please. I don't even know if it's an error in my code or in Android Studio. Thank you in advance!!!
The problem is that you are not awaiting NetInfo.fetch().
Write the code under NetInfo.fetch() in NetInfo.fetch().then(... your remaining useEffect code...).
Like this:
useEffect(() => {
NetInfo.fetch().then((state) => {
if (state.isConnected) {
findTbVeic()
.then(a => setDadosVeic(a))
.then( dadosVeic.map(item => {
// ENVIA DADOS PARA A API
fetch('url API', {
method: 'POST',
body: JSON.stringify({
username: item.username,
placa: item.placa,
atividade: item.atividade,
data_inic: item.data_inic,
km_inic: item.km_inic,
data_final: item.data_final,
km_final: item.km_final
}),
headers: {
'Content-type': 'application/json; charset=UTF-8',
},
})
//ALTERA O 'INTEGRADO' == 1
Tb_veic_user.updateV( item.ID_veic_uso )
}))
}else{
console.log('sem conexao com a internet')
}
});
}, []);
For your other useEffect: The problem is that you can't change a state and than use that state in an useEffect drectly after. This is cause of the execution of the useEffect. It will only rerender when variables in the useEffect array change. For example:
const Test = () => {
const [test, setTest] = useState(false);
useEffect(() => {
fetchTest().then((data) => {
// lets say data.test is "true"
setTest(data.test); // set to true
// states in useEffect will keep the value they had when the useEffect started
// DONT:
console.log("test:", test): // --> "test: false"
// DO
console.log("test:", data.test): // --> "test: true"
});
}, []);
}
I understood what Maximilan said, and on that login page it worked really well. But on the 'veic' page I'm not so lucky
useEffect(() => {
findByUserna( route.params.paramKey )
.then(
findByV(route.params.paramKey)
.then(
d => setDados(d)
),
console.log('use effect 1 ------>',dados)
)
.then(
dados.map(
item => setIDVeic(item.ID_veic_uso)
),
console.log('use effect 2 ------>',IDVeic)
)
},[])
When opening the screen, the consoles are empty, the variable is not saved, but when updating, it works, the variables are saved and shown in the console normally:
//The first time, console:
use effect 1 ------> Array []
use effect 2 ------> null
ENCONTRADO de tb_user o ID_user, username, nome_empresa ---> SORAIA
ENCONTRADO de tb_veic_user o ID_veic_uso onde kmf=null
//The second time, console:
use effect 1 ------> Array [
Object {
"ID_veic_uso": 4,
},
Object {
"ID_veic_uso": 7,
},
]
use effect 2 ------> 7
I just finishing setting up my socket in my react native and nodejs project and still my flatlist does not update instantly when a message is sent, i need to refresh the app in order for it to update.
I thought that by using socket this will work but still it is not working. whenever i user opens a chat i get eg. user: 1 has joined conversation 1 in the console which indicates that the socket is working.
Client Side
function ChatScreen({route,navigation}) {
const message = route.params.message;
const [messages, setMessages] = useState(message.Messages);
const [text, setText] = useState('');
const [socket, setSocket] = useState(null);
const { user } = useAuth();
const index = route.params.index;
const updateView = route.params.updateView;
useEffect(() => {
const newsocket =io.connect(socketURL)
setMessages(messages);
newsocket.on('connect', msg => {
console.log(`user: ${user.id} has joined conversation ${message.id}`)
setMessages(messages=>messages.concat(msg))
setSocket(newsocket)
});
return()=>newsocket.close;
}, []);
const onSend = (ConversationId,senderId,receiverId,message) => {
messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
setText("")
const to = (user.id===route.params.message.user1?
route.params.message.user2:route.params.message.user1)
socket.emit('message', { to: to, from: user.id, message, ConversationId });
};
const updateText=(text)=>{
setText(text);
}
return (
<FlatList
inverted
data={message.Messages}
keyExtractor={(message) => message.id.toString()}
renderItem={({item,index})=>(
<>
<Text>
{moment(item.createdAt).fromNow()}
</Text>
<MessageBubble
text={item.message}
mine={item.senderId !== user.id}
/>
</>
)}
/>
<View style={styles.messageBoxContainer}>
<TextInput
onChangeText={updateText}
value={text}
/>
<TouchableOpacity
onPress={()=>{onSend(message.id,user.id,(user.id===message.user1?
message.user2:message.user1),text)}}>
</TouchableOpacity>
</View>
);
}
Server Side
const express = require("express");
const app = express();
const http = require("http");
const socket = require("socket.io")
const server=http.createServer(app);
const io =socket(server)
io.on('connection', (socket) => {
console.log("connected")
socket.on('message', (data) => {
console.log(data)
socket.join(data.ConversationId);
io.sockets.in(data.to).emit('send_message', { message:
data.message, to: data.to });
});
});
UPDATE
Client Side
const message = route.params.message;
const [messages, setMessages] = useState([]);
const [text, setText] = useState('');
const [socket, setSocket] = useState(null);
const { user } = useAuth();
useEffect(() => {
const newsocket =io.connect("http://192.168.1.103:9000")
newsocket.on('connect', msg => {
console.log(`user: ${user.id} has joined conversation
${message.id}`)
setSocket(newsocket)
setMessages(message.Messages)
});
newsocket.on("send_message", (msg) => {
console.log("this is the chat message:", msg);
setMessages([ { ...message.Messages },...messages]);
});
return()=>newsocket.close;
}, []);
const onSend = (ConversationId,senderId,receiverId,message) => {
console.log("sent")
messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
setText("")
const to = (user.id===route.params.message.user1?
route.params.message.user2:route.params.message.user1)
socket.emit(
'message', { to: to, from: user.id, message,ConversationId });
};
const updateText=(text)=>{
setText(text);
}
<FlatList
inverted
data={messages}
keyExtractor={(message) => message.id.toString()}
renderItem={({item,index})=>(
<>
<Text>
{moment(item.createdAt).fromNow()}
</Text>
<MessageBubble
text={item.message}
mine={item.senderId !== user.id}
/>
</>
)}
bounces={false}
/>
<View style={styles.messageBoxContainer}>
<TextInput
onChangeText={updateText}
value={text}
/>
<TouchableOpacity
onPress={()=>{
onSend(
message.id,
user.id,
(user.id===message.user1?message.user2:message.user1),
text
)}}
>
<Text>Send</Text>
</TouchableOpacity>
</View>
Server Side
io.on('connection', (socket) => {
console.log("connected")
socket.on('message', (data) => {
console.log(data)
socket.emit('send_message', { message: data.message, receiverId:
data.to,senderId:data.from,conversationId:data.ConversationId })
});
});
Using the updated code, when i open a chat i get
user: 43 has joined conversation 4 ---- on client side console
connected ---- on server side console
Using the updated code, when i send a message i get
this is the chat message: Object {
"conversationId": 25,
"message": "You",
"receiverId": 47,
"senderId": 43,
} --- in my client side console
{ to: 47, from: 43, message: 'You', ConversationId: 25 } ---- server
side console
But then i get an error
undefined is not an object (evaluating 'message.id.toString')
I think my problem is that i am not emitting the the message id correctly and therefore my flatlist does not know it. To get a message id, i need to store the message in db first
NEW UPDATE
Client Side
const message = route.params.message;
const [messages, setMessages] = useState([]);
const [text, setText] = useState('');
const [socket, setSocket] = useState(null);
const { user } = useAuth();
useEffect(() => {
const newsocket =io.connect(socketURL)
newsocket.on('connect', msg => {
console.log(`user: ${user.id} has joined conversation
${message.id}`)
setSocket(newsocket)
setMessages(message.Messages)
});
newsocket.on("send_message", (msg) => {
console.log("this is the chat message:", msg);
const data = [...messages];
console.log(data)
data.push(msg);
setMessages(data);
});
return(()=>newsocket.close());
}, []);
const onSend = (ConversationId,senderId,receiverId,message) => {
console.log("sent")
messagesApi.sendMessage({ConversationId,senderId,receiverId,message});
setText("")
const to = (user.id===route.params.message.user1?
route.params.message.user2:route.params.message.user1)
socket.emit(
'message', { to: to, from: user.id, message,ConversationId });
};
const updateText=(text)=>{
setText(text);
}
<FlatList
inverted
data={messages}
keyExtractor={(item,index)=>index.toString()}
renderItem={({item,index})=>(
<>
<Text>
{moment(item.createdAt).fromNow()}
</Text>
<MessageBubble
text={item.message}
mine={item.senderId !== user.id}
/>
</>
)}
bounces={false}
/>
<View style={styles.messageBoxContainer}>
<TextInput
onChangeText={updateText}
value={text}
/>
<TouchableOpacity
onPress={()=>{
onSend(
message.id,
user.id,
(user.id===message.user1?message.user2:message.user1),
text
)}}
>
<Text>Send</Text>
</TouchableOpacity>
</View>
Server Side
io.on('connection', (socket) => {
console.log("connected")
socket.on('message', (data) => {
console.log(data)
socket.emit('send_message', { message: data.message, receiverId:
data.to,senderId:data.from,conversationId:data.ConversationId })
});
});
Now using the new updated code when i send a message only the new message gets rendered to the sender without the previous messages, and the receiver does not receive anything while on the chat.
So from your answers I get the impression that in order to make it work you would need to do roughly the following:
On your client side you gotta have a socket listening for updates:
socket.on('send_message', (e) => doSomethingWith(e));
Once you have your socket listening to updates, you can treat the information received. The easiest way to make sure your component rerenders and shows the correct information is to use state. So upon receiving the message from the socket, you could set the messages
setMessages(socketMessage)
You then pass messages state to your data in Flatlist. I would also pass it in the extraData field also in Flatlist.
If you have redux in place, you may want to save the messages there, then there will be no need to set the local state in the component and you could just take it from props.
Hope this helps, if you have any additional questions don't hesitate to ask them.
Edit 1:
I'm just gonna copy the code from the solution you mentioned above:
useEffect(() => {
handleGetGroupMessage();
let socket = io(socketUrl);
socket.on("GroupChat", (msg) => {
console.log("this is the chat messages", chatMessages);
setChatMessages(chatMessages.concat(msg)); // this is the "doSomethingWith(e)"
});
}, []);
You receive your message via the socket and then have to do something with it. Not using redux? Set it to local state or to top level context, whatever works for your app.
Edit 2:
socket.on('connect', ...) is a standard event which socket understands. It's not your messages, you need to establish that apart.
Try this way
<FlatList
inverted
data={messages}
keyExtractor={(item,index) => index.toString()}
extraData={messages} // add this
renderItem={({item,index})=>(...)}
useEffect(() => {
...
newsocket.on("send_message", (msg) => {
console.log("this is the chat message:", msg);
// setMessages([ { ...message.Messages },...messages]); // remove this
// add this
const data = [...messages];
data.push(msg);
setMessages(data);
});
...
}, []);
hi i'm new on react native and i have a issue with asyncStorage. I want to store the cache state in my pdf screen. The cache is a parameter of the source and handle only boolean. I made an onPress which change a state and store it in my localstorage, it works and when i console.log my getItem it shows true or false too it works too. But here is my problem. Now i want to just use the true or the false from this getItem because the parameter cache can handle boolean only. The best i could get on my search was Promise Boolean for my function. So if you could help me it'll be incredible because i really don't know. Thank you a lot and sorry for my English.
Here's my code //
export class Liste extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
navigation : props.navigation,
route: props.route,
selectedIndex : this.selectedIndex,
page : this.page,
numberOfPages : this.numberOfPages,
filePath : [],
cache : false,
};
}
saveCache() {
AsyncStorage.setItem('cache', JSON.stringify(this.state.cache));
console.log(`store ${this.state.cache}`);
}
async getCache () {
const ta = await AsyncStorage.getItem('cache', (value) => {
JSON.parse(value)
})
console.log(ta)
}
navigateBack = () => {
this.state.navigation.goBack();
};
BackAction = () => (
<TopNavigationAction icon={BackIcon} onPress={this.navigateBack}/>
);
render() {
const {files} = this.state.route.params;
const cache = this.state.cache;
const bool = this.getCache();
return (
<>
<TopNavigation style={{ borderWidth: 1 }} title='Mes Articles' alignment='center' accessoryLeft={this.BackAction} />
<ViewPager
selectedIndex={this.state.selectedIndex}
onSelect={ index => this.setState({ selectedIndex: index })}>
{files.map((file, i) =>
<Layout style={styles.tab} level='2'>
<Text>{file.filename}</Text>
<Text>Article: {i + 1} / {files.length} page: {this.state.page} / {this.state.numberOfPages}</Text>
<View>
<TopNavigationAction icon = {emailIcon} onPress={() => Share.open({ title: 'Pdf file', message: `bonjour voici l'article pdf ${file.filename}`, url: `file:///${this.state.filePath[i]}`, subject: `Article Pdf ${file.filename}` })} status='Partager'>
Partager
</TopNavigationAction>
<TopNavigationAction icon = {pin} onPress ={() => this.saveCache(cache === true ? this.setState({cache : false}) : this.setState({cache : true}))} status='Partager'>
Partager
</TopNavigationAction>
<TopNavigationAction icon = {pin} onPress ={() => console.log(this.getCache())} status='Partager'>
Partager
</TopNavigationAction>
</View>
<Pdf
source={{ uri: `http://10.1.0.248/${file.path}/${file.filename}`, cache : bool}}
style={styles.pdf}
enablePaging={true}
onLoadComplete={(numberOfPages, filePath) => {
this.state.filePath.push(filePath);
this.setState({ numberOfPages: numberOfPages });
}}
onPageChanged={(page, numberOfPages) => {
this.setState({ page: page });
}}
/>
</Layout>
)}
</ViewPager>
</>
);
}
}
You can use it like this.
await AsyncStorage.getItem('cache'); returns a JSON stringified value which you could parse and use.
async getCache () {
const ta = await AsyncStorage.getItem('cache');
console.log(JSON.parse(ta))
}
Use it likewise
let ta = await AsyncStorage.getItem('cache');
ta = JSON.parse(ta);
So what I'm trying to do is fetching data from an API (works well), that has this autocomplete function.
Link to example: https://autocomplete.aws.dk/
Link to the guide: https://autocomplete.aws.dk/guide2.html
What is hard for me, is that the guide is HTML, and this is suppose to work in React Native.
So far I made an input field, that can detect when writing minimum two letters will show a list of addresses.
What I want is when the address is clicked, it takes that value and places it in the input field.
Heres my code:
The API fetch:
import React from "react";
import url from "./url";
export default class DawaFetch extends React.Component {
static defaultProps = {
options: {},
minCharacters: 2,
};
state = {
value: "",
suggestions: [],
};
handleChange = ({ target: { value } }) => {
this.setState({ value });
if (this.props.minCharacters <= value.length) this._fetch(value);
};
_fetch = (value) => {
fetch(
url("https://dawa.aws.dk/adresser/autocomplete", {
q: value,
["per_side"]: 100,
...this.props.options,
}),
{
method: "GET",
headers: {
"Accept-Encoding": "gzip, deflate",
},
}
)
.then((response) => response.json())
.then((json) => this.setState({ suggestions: json }))
.catch((err) => console.error("parsing failed", err));
};
render = () =>
this.props.children({ ...this.state, handleChange: this.handleChange });
}
And here is my view:
<DawaFetch>
{({ value, suggestions, handleChange }) => {
console.log(suggestions);
return (
<View>
<CustomInputs
type="text"
value={value}
onChange={handleChange}
/>
{suggestions.map((suggestion) => (
<TouchableOpacity>
<NormalText key={suggestion.adresse.id}>{suggestion.tekst}</NormalText>
</TouchableOpacity>
))}
</View>
);
}}
</DawaFetch>
Tried different solutions by making it a FlatList with renderItem, and making an onPress function, but I could never make it work.
Hopefully someone can guide me in the right direction, I might been overthinking this.
React-Native TextInput onChange value is not available inside the target as it's available in HTML, Remove target from handleChange function like below, also it's not onChange it's onChangeText in TextInput.
handleChange = (value) => {
this.setState({ value });
if (this.props.minCharacters <= value.length) this._fetch(value);
};
You can achieve your desired functionality in a very simple manner.
Add this to your DawaFetch class.
OnItemSelection=(address)=>{
this.setState({value: address})
}
Add this to your render Function
render = () =>
this.props.children({ ...this.state, handleChange: this.handleChange, OnItemSelection: this.OnItemSelection });
}
Then make these changes in your DawaFetch component
<DawaFetch>
{({ value, suggestions, handleChange, OnItemSelection }) => {
console.log(suggestions);
return (
<View>
<CustomInputs
type="text"
value={value}
onChangeText={handleChange}
/>
{suggestions.map((suggestion) => (
<TouchableOpacity onPress={()=> OnItemSelection(suggestion.adresse)}>
<NormalText key={suggestion.adresse.id}>{suggestion.tekst}</NormalText>
</TouchableOpacity>
))}
</View>
);
}}
</DawaFetch>
Edit:Here is Snack having solution
https://snack.expo.io/#waheed25/bad-raisins