Not getting any return value from function [React Native] - function

I have this menu where I filter the button when user is logged and I'm accessing a function from a separate file to check out if user is logged or not.
From menu
import { IsLogged } from '../GlobalFunctions';
const SubDrawer1 = ({ data, onChange }) => (
<View>
{
IsLogged() ? (
<View>
<TouchableOpacity onPress={()=>{onChange('LogoutScreen')}}>
<Text>Logout</Text>
</TouchableOpacity>
</View>
) : (<View />)
}
</View>
);
export default SubDrawer1;
From GlobalFunctions
export function IsLogged(){
AsyncStorage.getItem('userId').then((userId) => {
return userId ? true : false
})
}
From menu I call out IsLogged() function but the value is undefined when I console.log it. It supposed to return either true or false.

You are trying to call a async function, so you need to add some extra code. Try the following.
SubDrawer1
import { Text, View, TouchableOpacity } from "react-native";
import React, { Component } from "react";
import { IsLogged } from "../GlobalFunctions";
const SubDrawer1 = async ({ data, onChange }) => {
const status = await IsLogged();
if (status === true) {
return (
<View>
<View>
<TouchableOpacity
onPress={() => {
onChange("LogoutScreen");
}}
>
<Text>Logout</Text>
</TouchableOpacity>
</View>
</View>
);
} else {
return (
<View>
<View />
</View>
);
}
};
export default SubDrawer1;
'IsLogged()' Global function
export function async IsLogged(){
let userId = await AsyncStorage.getItem('userId');
return userId ? true : false
}
'SubDrawer1' using class
...
import SubDrawer1 from "./SubDrawer1"; // import your 'SubDrawer1' component
var subDrawer1Component; // declare a variable for your rendering component
//Your main class
export default class ClassName extends Component<Props> {
componentDidMount() {
this.getComponentInfo(); //Call this method to get function
}
getComponentInfo = async () => {
subDrawer1Component = await SubDrawer1();// Will take the component
this.setState({ isDataGet: true });
};
render() {
return (
...
{subDrawer1Component}
...
);
}
}
...

because AsyncStorage will take some time, and before that function completes its execution. (Because everything in JS is asynchronous)
So just make it wait until it finishes getting an item,
export function async IsLogged(){
let userId = await AsyncStorage.getItem('userId');
return userId ? true : false
}

Related

Objects are not valid as a React child (found: object with keys { my keys })

when I submit my form with the const onSubmit, I fetch data. If the submit form is ok, I want to extract the data I get from my api. So I use, setState reponse : my data, and then I want to pass this data (reponse) to the component SingleLayout.
But it doesn't work. I get this error : [Error: Objects are not valid as a React child (found: object with keys {ID, Post Title, post_date, Prix, Surface, Ville, Category, featured_image, mandats_signes, date_de_signature_du_compromis}). If you meant to render a collection of children, use an array instead.]
Here the code :
export default class QueryChild extends Component {
state = {
username: "",
password: "",
isLogged: null,
email: "",
reponse: '',
id: 4577
}
constructor(props) {
super(props);
this.render();
}
onSubmit = async() => {
const fetchValue = 'myAPI/suivi-dossier?' + 'username=' + this.state.username + '&password=' + this.state.password + '&id=' + this.state.id
try {
await fetch(fetchValue, {
method: 'GET'
})
.then((response) => response.json())
.then((responseJson) => {
if(responseJson.success === true) {
// I want to extract this :
this.setState({ reponse: responseJson.message })
this.setState({ isLogged: true })
} else {
this.setState({reponse : responseJson.message });
console.log(this.state.reponse)
}
// this.setState({
// data: responseJson
// })
})
.catch((error) => {
console.error(error);
});
} catch (err) {
console.log(err)
}
}
render() {
if(this.state.isLogged === true) {
// when user is Logged, I want to pass this.state.reponse to my component SingleLayout
// but I get the error : [Error: Objects are not valid as a React child
// (found: object with keys {ID, Post Title, post_date, Prix, Surface, Ville,
// Category, featured_image, mandats_signes, date_de_signature_du_compromis}). If you
// meant to render a collection of children, use an array instead.]
const SingleComponent = this.state.reponse.map(message => <SingleLayout key={message.ID} table={message}/> )
return (
<SafeAreaView>
{SingleComponent}
</SafeAreaView>
);
} else {
return (
<View style={styles.container}>
<ScrollView>
<ImageBackground source={image} resizeMode="cover" style={styles.image}>
<Spacer taille={70} />
<View style={styles.content}>
<Image
style={styles.imgLogo}
source={require('../../logo.png')}
/>
<Text style={styles.logo}>Pour des raisons de sécurité, veuillez entrer vos Identifiants</Text>
<View style={styles.inputContainer}>
<Text style={styles.textBasique}>{this.state.reponse}</Text>
<TextInput
placeholder='Identifiant ou adresse email'
style={styles.input}
value={this.state.username}
onChangeText={val => this.setState({ username: val})}
/>
<TextInput
placeholder='Mot de passe'
style={styles.input}
value={this.state.password}
secureTextEntry= {true}
onChangeText={val => this.setState({ password: val})}
/>
<Spacer taille={10} />
<Button title='Se Connecter' onPress={this.onSubmit}/>
<Spacer taille={10} />
</View>
</View>
<Spacer taille={200} />
</ImageBackground>
</ScrollView>
</View>
)
}
}
}
Thank you.
The response that comes from the server is an object. Since the "map" function only works with an array so, if you want to run this code you've to wrap "responseJson.message" into the array.
if(responseJson.success === true) {
this.setState({ reponse: [responseJson.message] })
this.setState({ isLogged: true })
}
Yes I get similar error after applying the solution because I found that the error comes from the setState reponse. So I added JSON.stringify and now the error is gone.
The code of Single Layout :
const SingleLayout = (props) => {
let id = props.id
let table = props.table
console.log(table)
const { colors } = useTheme();
return (
<View style={[styles.container, {backgroundColor: colors.background}]}>
<Text>Bravo</Text>
</View>
)
}
Now with the solution : const SingleComponent = Object.keys(this.state.reponse).map(key => )
it works but it send caracters one by one
SO I finally solved my problem :
the code i change :
QueryChild.tsx :
if(responseJson.success === true) {
//here :
this.setState({ reponse: JSON.stringify(responseJson.message) })
this.setState({ isLogged: true })
and I directly return SingleLayout like that :
return (
<SafeAreaView>
<SingleLayout table={this.state.reponse} />
</SafeAreaView>
Now I can access this.state.reponse into my SingleLayout :
const SingleLayout = (props) => {
let id = props.id
let table = props.table
const myObj = JSON.parse(table);
console.log(myObj[0].mandats_signes)
console.log(myObj[0].ID)
console.log(myObj[0].Category)
//etc...
const { colors } = useTheme();
return (
<View style={[styles.container, {backgroundColor: colors.background}]}>
<Text>Bravo</Text>
</View>
)
}
it's not a good practice to pass JSON and then parse.
I solved it and here is the link with the same solution that I presented to you:
https://codesandbox.io/s/peaceful-bouman-qyi5y?file=/src/App.js

MQTT Response with React Native

I am currently making an IoT App that I'm trying to connect to a raspberry pi using MQTT. I use the react_native_mqtt package. I use the code posted by simaAttar from here: How to use MQTT on React Native? . The problem I have it doesnt always update my code when I alter it and save. What I'm trying to achieve is to receive a JSON formatted string from the rasp and use that to fill a FlatList with react-native-elements ListItem. But the data received is undefined, even though yesterday I did have it working for a second, it won't work anymore now.
Any help is appreciated.
EDIT: this is the code (forgot to post it)
import React, {Component} from 'react';
import init from 'react_native_mqtt';
import AsyncStorage from '#react-native-community/async-storage';
import {
ActivityIndicator,
StyleSheet,
Text,
View,
FlatList,
TouchableOpacity,
TextInput,
Button,
Alert,
} from 'react-native';
import {ListItem} from 'react-native-elements';
init({
size: 10000,
storageBackend: AsyncStorage,
enableCache: true,
sync: {},
});
export default class AllPeople extends Component {
constructor() {
super();
this.onMessageArrived = this.onMessageArrived.bind(this);
this.onConnectionLost = this.onConnectionLost.bind(this);
const client = new Paho.MQTT.Client(
'onto.mywire.org',
8080,
'Client-' + Math.random() * 9999 + 1,
);
client.onMessageArrived = this.onMessageArrived;
client.onConnectionLost = this.onConnectionLost;
client.connect({
onSuccess: this.onConnect,
useSSL: false,
onFailure: (e) => {
console.log('Error: ', e);
},
});
this.state = {
message: [''],
data: [],
isLoading: true,
client,
messageToSend: '',
isConnected: false,
};
}
onConnect = () => {
console.log('Connected');
const {client} = this.state;
client.subscribe('/app/to/allpeople');
this.setState({
isConnected: true,
error: '',
isLoading: true,
messageToSend: 'allpeople',
});
this.sendMessage();
};
onMessageArrived(entry) {
console.log("Nieuwe Test 1:")
console.log("PayloadMEssage: "+entry.payloadMessage);
console.log("Payload tostring: "+entry.payloadMessage.toString())
//this.setState({data: entry, isLoading: false});
}
sendMessage = () => {
console.log('message send.');
var message = new Paho.MQTT.Message(this.state.messageToSend);
message.destinationName = '/app/from';
if (this.state.isConnected) {
this.state.client.send(message);
} else {
this.connect(this.state.client)
.then(() => {
this.state.client.send(message);
this.setState({error: '', isConnected: true});
})
.catch((error) => {
console.log(error);
this.setState({error: error});
});
}
};
onConnectionLost(responseObject) {
if (responseObject.errorCode !== 0) {
console.log('onConnectionLost:' + responseObject.errorMessage);
this.setState({error: 'Lost Connection', isConnected: false});
}
}
render() {
return (
<View style={styles.container}>
{this.state.isLoading ? (
<ActivityIndicator />
) : (
<FlatList
keyExtractor={keyExtractor}
data={this.state.data}
renderItem={Item}
/>
)}
</View>
);
}
}
const keyExtractor = (item, index) => login.username.toString();
const Item = ({item}) => {
return (
<TouchableOpacity>
<ListItem
title="TestTitle" //{item.results.name.first}
titleStyle={{fontWeight: 'bold'}}
leftIcon={<MCIcons name="account" size={36} color="dodgerblue" />}
subtitle={item.results.name.last}
rightTitle={item.results.registered.date}
rightTitleStyle={{fontSize: 14}}
chevron
bottomDivider
/>
</TouchableOpacity>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
},
});
I have managed to fix it by changing entry.payloadMessage to entry.payloadString. Apparentyly I changed it during the editing of my code.

How can I turn a function used in many components into its own component which I can reuse across the app?

I have a fetch request used on multiple pages, and would like to turn it into a component to simply call in whenever it's needed. This is proving to be harder than I thought, and it's bring up a number of issues.
I have tried using the wrappedComponent function but not sure if that's the solution as it's still not working. It's now saying that the fetchPosts class constructor cannot be invoked without new.
const that = this;
fetch ('/testrouter')
.then (response => {
return response.json();
}).then(jsonData => {
that.setState({posts:jsonData})
}).catch(err => {
console.log('Error fetch posts data '+err)
});
}
This is what I want to turn into a component, so that I can just call it by it's name from another one inside componentDidMount. I have tried doing this:
function fetchPosts(WrappedComponent) {
class FetchPosts extends Component {
constructor(props) {
super(props)
this.state = {
posts: []
}
}
fetchAllPosts() {
const that = this;
fetch ('/testrouter')
.then (response => {
return response.json();
}).then(jsonData => {
that.setState({posts:jsonData})
}).catch(err => {
console.log('Error fetch posts data '+err)
});
}
render() {
return (<WrappedComponent
fetchAllPosts = {this.fetchAllPosts})
/>);
}
}
return FetchPosts;
}
export default fetchPosts
Then importing it and calling it with fetchPosts but it's not working.
I was hoping I would be able to create a component, add the code then import the component, but this is not working.
You might want to create a custom hook to do this:
useFetch.jsx
import React, { useState, useEffect } from 'react'
const useFetch = (url) =>
const [state, setState] = useState({ loading: true, data: null, error: null })
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => setState(state => ({ ...state, loading: false, data }))
.catch(error => setState(state => ({ ...state, loading: false, error }))
},[])
return state
}
export default useFetch
MyComponent.jsx
import React from 'react'
import useFetch from './useFetch.jsx'
const MyComponent = () => {
const data = useFetch('/testrouter')
return (<>
{ data.loading && "Loading..." }
{ data.error && `There was an error during the fetch: {error.message}` }
{ data.data && <Posts posts={data.data}/> }
</>)
}

Pass database data from express.js server to react.js component

This is a react app with an express.js backend. I have a mysql database connected to my server.js file and it seems to be connected fine. My issue is I want to pass that data to my react app and display it there.
My server.js database connection
app.get('api/listitems', (req, res) => {
connection.connect();
connection.query('SELECT * from list_items', (error, results, fields) => {
if (error) throw error;
res.send(results)
});
connection.end();
});
So this should grab the 'list_items' records from the database
Below is my react.js code. I would like to display the records under the grocery list h3.
import React, { Component } from 'react';
import './App.scss';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: ['first item']
};
}
render() {
return (
<div className="App">
<h3>Grocery List</h3>
{this.state.data}
</div>
);
}
}
export default App;
I know this is a simple concept but I am new to backend development. The tutorials I have found have gotten me to this point, but I have had an issue finding one that simply explains how to pass and display data from the backend to frontend.
**index.js**
import React from 'react';
import { render } from 'react-dom';
import App from './components/app';
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux';
import store, { history } from './store';
const route = (
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
)
render(route,document.getElementById('app'))
**action/listItemAction.js**
export const ListItemSuccess = (data) => {
return {type: 'GET_LIST_ITEMS'};
}
export const getListItems = () => {
return (dispatch) => {
return axios.get('http://localhost:5000/api/listitems')
.then(res => {
dispatch(ListItemSuccess(res));
})
.catch(error=>{
throw(error);
})
};
}
**reducers/listItems.js**
const listItems = (state = [], action) => {
switch(action.type){
case 'GET_LIST_ITEMS':
return action.res.data;
default:
return state;
}
}
export default listItems;
**store.js**
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk'
import listItems from './reducers/listItems.js';
const store = createStore(listItems, compose(
applyMiddleware(thunk),
window.devToolsExtension ? window.devToolsExtension() : f => f
));
export default store;
**App.js**
import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import './App.scss';
import getListItems from './action/listItemAction.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: true,
};
}
componentWillMount() {
this.props.getListItems().then(() => {
this.setState({data: this.props.listItems, isLoading:false});
}).catch(error => {
throw(error);
});
}
render() {
return (
<div className="App">
<h3>Grocery List</h3>
{this.state.isLoading ? <p>Loading...</p>
: this.state.error ? <p>Error during fetch!</p>
: (
<ul>
this.state.data.map(item => <li>{item}</li>)
</ul>
)}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
listItems: state.listItems
};
};
const mapDispatchToProps = (dispatch) => {
return {
getListItems: bindActionCreators(getListItems, dispatch),
};
};
export default connect(mapStateToProps,mapDispatchToProps)(App);
You want to make a GET request to your backend to asynchronously fetch the data. If you want the data when your App component first mounts, you can use fetch in componentDidMount to call to your backend endpoint. Here's an example, with a loading fallback and basic error handling:
class App extends Component {
state = {
data: [],
loading: true,
error: false
}
...
componentDidMount() {
// Pick whatever host/port your server is listening on
fetch('localhost:PORT/api/listitems')
.then(res => { // <-- The `results` response object from your backend
// fetch handles errors a little unusually
if (!res.ok) {
throw res;
}
// Convert serialized response into json
return res.json()
}).then(data => {
// setState triggers re-render
this.setState({loading: false, data});
}).catch(err => {
// Handle any errors
console.error(err);
this.setState({loading: false, error: true});
});
}
render() {
return (
<div className="App">
<h3>Grocery List</h3>
// The app will render once before it has data from the
// backend so you should display a fallback until
// you have data in state, and handle any errors from fetch
{this.state.loading ? <p>Loading...</p>
: this.state.error ? <p>Error during fetch!</p>
: (
<ul>
this.state.data.map(item => <li>{item}</li>)
</ul>
)}
</div>
);
}
}
fetch won't reject on HTTP error status (404, 500), which is why the first .then is a little odd. The .catch will log the response here with the status, but if you want to see the error message from the server, you'll need to do something like this:
if (!res.ok) {
return res.text().then(errText => { throw errText });
}
See See https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch for more information, or explore other data fetching libraries like axios.

Can't access JSON data and print Begin and End only React Native

I'm trying to access to Begin and End inside JSON data but I can't. It just accesses and prints JSON data.
How can I print the Begin and End in separately FlatList?
Here is my code :
manage = date => {
this.setState({status: true})
this.setState({date:date})
const office_id=this.state.office_id;
const duration=this.state.duration;
const url='http://MyIP/api/timeApi';
axios.post(url,{office_id,date,duration})
.then(resp => this.setState({
testArray : JSON.stringify(resp.data),
}))
.catch(e)
{
alert(e);
}}
testFunction = () => {
var x = this.state.testArray;
return(
<Text>{x}</Text>
)
}
<DatePicker
date={this.state.date}
onDateChange={this.manage.bind(this) } />
in return
{
this.state.status ? <View>
<FlatList
data={this.state.testArray}
renderItem={this.testFunction}
/>
</View> : null
}
and here is my result
you need something like this , try to change it based on your code
import React, { Component } from 'react';
import {Text, View, FlatList ,Button} from 'react-native';
export default class Test extends Component {
constructor() {
super();
this.state = {
data: ['one', 'two', 'three', 'four', 'five'],
}
}
_keyExtractor = (item, index) => index.toString();
_renderItem = ({ item }) => (
<View>
<Text>{item}</Text>
</View>
);
manage = () => {
var x = this.firstAndLast(this.state.data);
this.setState({
data : x
})
}
firstAndLast(myArray) {
var firstItem = myArray[0];
var lastItem = myArray[myArray.length-1];
var newArray = [];
newArray.push(firstItem);
newArray.push(lastItem);
return newArray;
}
render() {
return (
<View>
<FlatList
data={this.state.data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
<Button title="click" onPress={() => this.manage()} />
</View>
);
}
}