activate async function on load screen - reactjs

Im trying to create a users list with my api using a async function, but I dont know how to user it on load screen, can you help me
export default class Dermatologistas extends Component{
state ={
errorMessage: null,
users: []
}
getUserList = async () => {
try {
const response = await api.get('/auth/list');
const { users } = response.data
console.log(response.data)
this.setState({ users });
} catch (response) {
this.setState({ errorMessage: response.data.error });
}
};
render(){
const users = this.state.users
console.log(users)
return(
<View >
how you can see I was using a button to load everything, but i wanted to load when the screen loads
<Button onPress={this.getUserList} title='carregar'/>
{this.state.users.map(user => (
<View key={user._id} style={{marginTop: 15, alignItems: 'center'}}>
<Text>{user.title}</Text>
<Text>{user.speciality}</Text>
<Button title = 'View Profile'onPress ={() => this.props.navigation.navigate('Profile')}/>
</View>
))}
</View>
)
}
}

componentDidMount() {
this.getUserList();
}

Related

How to display user specific data from firebase as a FlatList in React Native

I'm new to reactnative and firebase and i looked for any infomation on this but had no luck in figuring out how to do this. Basically i want to display data from firebase which is specific to the user currently logged in, ive gotten halfway thru but don't understand what to do next. can someone show me what the rest of the code needs to be
Heres my code:
class HomeScreen extends Component {
constructor() {
super();
this.state = {
uid: ''
}
}
readUserData() {
currentUser = firebase.auth().currentUser
var that = this
firebase.database().ref(`BorrowedBooks`).child(currentUser.uid).on('value', function (data) {
console.log(data.val())
});
}
signOut = () => {
firebase.auth().signOut().then(() => {
this.props.navigation.navigate('Login')
})
.catch(error => this.setState({ errorMessage: error.message }))
}
render() {
this.state = {
displayName: firebase.auth().currentUser.displayName,
uid: firebase.auth().currentUser.uid
}
return (
<View style={styles.container}>
<Text style = {styles.textStyle}>
Hello, {this.state.displayName}
</Text>
<View>
<FlatList/>
</View>
<Button
color="#3740FE"
title="Logout"
onPress={() => this.signOut()}
/>
<Button
color="#3740FE"
title="display books"
onPress={this.readUserData}
/>
</View>
);
}
}
This is what my firebase database looks like: firebase database
This is the response after console.log: console.log output
you need to store the data in an array before you can display it in FlatList
readUserData() {
currentUser = firebase.auth().currentUser
var that = this
firebase.database().ref(`BorrowedBooks`).child(currentUser.uid).on('value', function (data) {
//console.log(data.val())
let DATA = [];
if(data.exists()){
KEY = Object.keys(data.val());
KEY.forEach( (key_id) => {
let a = snapshot.val()[key_id];
a.key = key_id;
DATA.push(a);
})
that.setState({userData: DATA})
});
}
then you can display it in flatlist
<FlatList
data = {this.state.userData}
renderItem ={({item}) =>
//render Items here
}
/>

Refresh screen or component when navigate to it

I have two screens, one for displaying the records consuming an API and the other for registering.
the problem is that when I do a register and navigate to the display screen it does not update.
This is a construction of the screen:
constructor(props) {
super(props);
this.state = {isLoading: true, pendIsLoading: true, dataSource: [], contentStorageS:""}
};
fetchDados = async () => {
let usuario = await AsyncStorage.getItem("ASCOFAR_app_usuario");
try {
const response = await api.get("api/listaRegistros.php?usuario="+usuario);
const responseData = await response.data
if(responseData.status == "ERRO"){
this.setState({
isLoading: false,
dataSource: "",
})
}else{
this.setState({
isLoading: false,
dataSource: responseData,
})
}
console.log(response)
} catch (error) {
Alert.alert(error)
}
}
async componentDidMount () {
this.fetchDados();
this.atualizaState();
}
tirarLoad() {
if(this.state.isLoading == true){
return (
<ActivityIndicator size="large" color="#be152c"/>
)
}else if(this.state.dataSource == ""){
return (
<ScrollView >
<View style={{justifyContent:"center", alignItems:"center",}}>
<Image
style ={{width:150, height:150, marginTop:35}}
source={require('../assets/images/aguardando.png')}
/>
</View>
</ScrollView>
)
}else{
return (
<ScrollView>
<Text style={styles.tituloGrid}>Formularios Enviados</Text>
{this.state.dataSource.map(dados => (
<View style={styles.list} key={dados.id}>
<Text style={styles.listChild}>{dados.id}</Text>
<Text style={styles.listChild}>{dados.nome}</Text>
<Text>|</Text>
<Text style={styles.listChild}>{dados.endereco}</Text>
</View>
))}
</ScrollView>
)
}
}
<View style={styles.grid}>
{this.tirarLoad()}
</View>
I need to know how to do when navigating to this screen to update API consumption
Assuming you are using React-Navigation, did you try to addListener
focus react-navigation documentation
You could also do it by componentDidUpdate. I could not find the official documentation for doing it on 5.x. I believe it still works with 5.x. (Doc on 3.x)
import { withNavigationFocus } from "react-navigation";
componentDidUpdate(prevProps) {
if (prevProps.isFocused !== this.props.isFocused) {
this.fetchDados()
//or other similar onFocus function
}
}
export default withNavigationFocus(TabScreen);
Try re-rendering your Home screen after navigation
this.props.navigation.navigate('Home', {
onBack: () => this.refresh() //function to refresh screen,
});
import { withNavigationFocus } from "react-navigation";
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
() => {
this.refreshFetch();
this.refreshLocal();
}
);
componentWillUnmount() {
this.willFocusSubscription.remove();
}

How to modify state of a component from a routed component?

I'm building a react native application where users can create event and invite people.
But I'm having some problems modifying the state of the component from a routed component.
There is a createEvent screen where user tries to create event...on clicking on invite people button a new screen is rendered let's name it as invitePeopleScreen.
If i'm not wrong...I think I need to use redux.
The createEvent screen:
import React from 'react';
import {Button, Container, Form, Input, Item, Text, Textarea} from "native-base";
export default class createEventScreen extends React.Component{
constructor(props) {
super(props);
this.state = {
title: '',
description: '',
createdBy: '',
invites: []
};
}
createEvent () {}
render() {
return (
<Container>
<Text>Create An Event </Text>
<Form>
<Item rounded>
<Input keyboardType="default"
placeholder="Enter the event title"
onChangeText={ title => this.setState({ title: title }) } />
</Item>
<Item rounded>
<Textarea keyboardType="default"
placeholder="Enter the event description"
onChangeText={ description => this.setState({ description: description }) } />
</Item>
</Form>
<Button rounded onPress={ () => { this.props.navigation.navigate('invitePeople') }}>
<Text>Invite People</Text>
</Button>
<Button rounded onPress={this.createEvent}>
<Text>Create Event</Text>
</Button>
</Container>
)
}
}
Here is the invitePeople Screen:
import React from 'react';
import { Container } from "native-base";
export default class inviteUsersScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
username: ''
}
}
addInvite = (username) => {
// push the username into the invites array of createEventScreen
}
render() {
return (
<Container>
<Text>Invite People </Text>
<Form>
<Item rounded>
<Input keyboardType="default"
placeholder="Enter the username"
onChangeText={ (username) => {this.setState({ username: username)})} />
</Item>
</Form>
<Button rounded onPress={ () => { this.addInvite(this.state.username) }}>
<Text>Submit</Text>
</Button>
);
}
}
I am exactly not sure what code will go into addInvite function.
You have three options to achieve this, option 1: pass a function as a prop to the next screen, option 2: use async storage, option 3: Redux.
Option: 1.
in your CreateEventScreen pass a function to the second screen as prop.
addInvite = username => {
this.setState({
invites: [...this.state.invites, username],
});
};
<Button
rounded
onPress={() => {
this.props.navigation.navigate('InvitePeople', {
addInvite: this.addInvite,
});
}}>
<Text>Invite People</Text>
</Button>
In your InviteUsersScreen, get the function and pass username.
addInvite = username => {
// push the username into the invites array of createEventScreen
const addInvite = this.props.navigation.getParam('addInvite', () => {
alert('No function was passed');
});
addInvite(username);
};
Option 2: AsyncStorage
import {AsyncStorage} from 'react-native';
// create function for saving items to storage
export const SaveItem = async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
console.log('saved')
} catch(e) {
console.log(e)
}
};
// create function for saving items to storage
export const ReadItem = async key => {
try {
var result = await AsyncStorage.getItem(key);
return result;
} catch (e) {
return e;
}
};
Then you can add items to the storage in your InviteUsersScreen.
addInviteWithStorge = username => {
const usernames = [...this.state.storageUsernames, username];
this.setState({
storageUsernames: usernames,
username: '',
});
const invites = JSON.stringify(usernames);
SaveItem('invites', invites)
.then(res => {
console.log('saved', res);
})
.catch(e => console.warn(e));
};
Retrieve items in your CreateEventScreen.
ReadItem('invites')
.then(res => {
if (res) {
const invites = JSON.parse(res);
this.setState({
invites: invites,
});
}
})
.catch(e => console.warn(e));
Demo
Something like that perhaps:
addInvite = (e, username) => {
e.preventDefault();
this.setState({
list: [...this.state.list, username]
})
}
Assuming you add to your state a list prop

React native Filtering API flatlist

I'm building my first react native app and connected my app to a mockable API
Before had I had a data.js file, but recently wanted to test the app with an live API.
Now I'm having problems filtering trough my API. Before hand I would import my Data.JS file and extract the object and put it in my state. Then I would set that equal to the filteredObject.
Now I've replaced my data file with my API
I've got a test running here
What I'm expecting:
To filter trough my FlatList
What I'm getting:
undefined is not an object (evaluating 'row.restraunt.indexOf')
Fetching API
export default class FetchExample extends React.Component {
static navigationOptions = {
header: null,
};
constructor(props){
super(props);
this.state ={
isLoading: true,
}
}
componentDidMount(){
return fetch('https://demo3381137.mockable.io/')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.restraunts,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
Filtering trough API
setSearchText(event) {
const searchText = event.nativeEvent.text;
// const textLength = this.state.rows.length;
const filteredTexts = this.state.dataSource.filter(row => {
return row.restraunt.indexOf(searchText) !== -1;
});
console.log("text: " + JSON.stringify(filteredTexts));
this.setState({
searchText,
filteredRows: filteredTexts
});
}
List Component
renderRow = (rowData) => {
return (
<View>
<Text>
{rowData.item.restraunt}, {rowData.item.type}
</Text>
</View>
)
}
Rendering FlatList
render() {
if(this.state.isLoading){
return(
<View style={styles.loading}>
<ActivityIndicator/>
</View>
)
}
return (
<View style={styles.container}>
{console.log(this.state.dataSource)}
<View style={styles.SearchBarContainer}>
<TextInput
placeholder="Search"
value={this.state.searchText}
onChange={this.setSearchText.bind(this)}
style={styles.searchBar}
underlineColorAndroid="black"
selectionColor="black"
/>
</View>
<FlatList
style={styles.listContainer}
data={this.state.dataSource}
renderItem={this.renderRow}
keyExtractor={(item, index) => index.toString()}
/>
</View>
)
}
It looks like the data returned from your API is inconsistent; for some rows restaurant is not present.
Consider revising your setSearchText() method like so, to account for row items that do not include the restraunt string field:
setSearchText(event) {
const searchText = event.nativeEvent.text;
const filteredTexts = this.state.dataSource.filter(row => {
/* If row.restraunt is present as a string, and includes searchText */
return (typeof row.restraunt === 'string') &&
row.restraunt.includes(searchText)
});
this.setState({
searchText,
filteredRows: filteredTexts
});
}
Also note the use of includes() here, which you may find a more concise alternative for this filtering behaviour. Hope that helps!
Update
Also, for the filtering to take effect, remember to update the data prop on <FlatList/> to your states filteredRows field, rather than dataSource. Lastly, keep in mind that the filtering is also case-sensitive.
Update 2
To achieve the desired filtering behaviour, you could make the following adjustments to your component:
componentDidMount(){
return fetch('https://demo3381137.mockable.io/')
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
/* Keep this, we'll base filtering on this data set */
dataSource: responseJson.restraunts,
/* Add this, to track what is presented to the user */
viewSource: responseJson.restraunts,
}, function(){
});
})
.catch((error) =>{
console.error(error);
});
}
render() {
if(this.state.isLoading){
return(
<View style={styles.loading}>
<ActivityIndicator/>
</View>
)
}
return (<View style={styles.container}>
<View style={styles.SearchBarContainer}>
<TextInput
placeholder="Search"
value={this.state.searchText}
onChange={this.setSearchText.bind(this)}
style={styles.searchBar}
underlineColorAndroid="black"
selectionColor="black"
/>
</View>
{/* Use state.viewSource as the data source for FlatList */}
<FlatList
style={styles.listContainer}
data={this.state.viewSource}
renderItem={this.renderRow}
keyExtractor={(item, index) => index.toString()} />
</View>)
}
setSearchText(event) {
const searchText = event.nativeEvent.text;
const filteredTexts = this.state.dataSource.filter(row => {
/* When no search text present, do not apply filtering */
if(!searchText) {
return true;
}
/* If row.restraunt is present as a string, and includes searchText */
return (typeof row.restraunt === 'string') &&
row.restraunt.includes(searchText)
});
this.setState({
searchText,
/* Update viewSource to ensure that filtered data is displayed */
viewSource: filteredTexts
});
}

How to capture videos with react-native-camera module?

I can capture pictures with this module without any problem, but when I try to record video, I can't seem to find where the recorded video is (or maybe no video was even recorded at all). Here is my CameraScreen:
import Camera from 'react-native-camera';
const { CaptureMode, CaptureTarget } = Camera.constants;
const { video: captureModeVideo, still: captureModePhoto } = CaptureMode;
class CameraScreen extends Component {
constructor(props) {
super(props);
this.state = {
captureMode: captureModePhoto,
isRecording: false
};
this.onCapture = this.onCapture.bind(this);
this.onSwitchCaptureMode = this.onSwitchCameraMode.bind(this);
}
onCapture() {
const { captureMode, isRecording } = this.state;
if (isRecording) {
this._camera.stopCapture();
this.setState({ isRecording: false });
return;
}
if (captureMode === captureModeVideo) {
this.setState({ isRecording: true });
}
this._camera.capture({ mode: captureMode })
.then((result) => console.log(result))
.catch((error) => console.log(error));
}
onSwitchCaptureMode() {
if (this.state.captureMode === captureModeVideo) {
this.setState({ captureMode: captureModePhoto });
} else {
this.setState({ captureMode: captureModeVideo });
}
}
render() {
const { captureMode } = this.state;
return (
<Camera
ref={(ref) => this._camera = ref}
style={{ flex: 1 }}
captureMode={captureMode}
captureTarget={CaptureTarget.disk}
>
<TouchableOpacity onPress={this.onCapture}>
<Icon
name='camera-alt'
...
...
/>
</TouchableOpacity>
<TouchableOpacity onPress={this.onSwitchCaptureMode}>
<Icon
name='...'
...
...
/>
</TouchableOpacity>
</Camera>
);
}
}
export default CameraScreen;
When I'm taking photos, the console.log(result) statement logs the path of the photo without a problem, but when captureMode === captureModePhoto, I don't have any logs in my debugger, is there something I'm doing wrong? I omitted many stylings to make the code more understandable
This is a silly mistake
The code posted by me works absolutely fine, but I have to test it on a real device. A simulator supports taking images (it generates some image with a random background color), but doesn't support taking videos. Therefore, problem solved

Resources