When and how often does the component re-render as users type information in a form? - react-native

Let’s say there is a code below where I listen to the event with onChangeText inside MyTextInput class. I update the state in onChangeText, which means the component will re-render.
When and how often does the component re-render as users type information in a form? I’m asking because I don’t believe it’s a good practice to re-render unnecessarily when the users are still in the middle of typing information.
export default class MyTextInput extends Component {
this.state = { text: '' };
render() {
return (
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
);
}
}

The entire component doesn't re-render just the text box, read this for more information regarding setState and stopping multiple rendering https://itnext.io/react-setstate-usage-and-gotchas-ac10b4e03d60

Related

React-Native TextInput for registering a user Why is the typed text is not displaying or being stored into the setInput object?

Hello I am trying to navigate creating a text input on React-Native that lets the user enter their email password and name and stores it in the object. But it is not working how I expected and I am not sure where I have gone wrong. I have looked at similar projects online but most are done with React not react-natie and even still when i try their implementation it still doesnt fix the text not displaying as i type or allowing it to be store when the user presses the register button.
import { Text, View, TextInput, Button, StyleSheet} from 'react-native';
import {useState} from 'react';
export default function Home() {
const [input, setInput] = useState({
fullName:"",
email:"",
password: "",
});
const inputHandler = (e) => {
let name = e.target.fullName
let value = e.target.value;
setInput({
...input,
[name]: value,
});
};
const registerUser = (e) => {
e.preventDefault();
console.log(input)
setInput({
fullName:"",
email: "",
password:"",
});
};
return (
<View >
<Text style={styles.welcome}>
Welcome! Please Register Below
</Text>
<TextInput style={styles.input} placeholder="Name" value={input.fullName} onChangeText={inputHandler}/>
<TextInput style={styles.input} placeholder="Email" value={input.email} onChangeText={inputHandler}/>
<TextInput style={styles.input} placeholder="Password" value={input.password} onChangeText={inputHandler} />
<View style={styles.button}>
<Button title="Register" onPress={registerUser} />
</View>
<View style={styles.button}>
<Button title="Already Registered? Click here to login" onPress={()=> register()} />
</View>
</View>
);
}
const styles = StyleSheet.create({
welcome:{
padding:10
},
input: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
borderColor:'black',
borderWidth: 2,
margin:3
},
button:{
margin:5
}
});```
I have tried this.input.fullName in the value prop but that give me an error as that is not the way i defined it with my handlers. I also could go back to just using seperate states for each input like [name,setName] [password,setPassword] ect... but I would really like to understand where my knowledge is lacking for utilizing TextInput to pass user information and storing it.
From looking through similar stackoverflow questions I also tried changing my onChangeText to this
`onChangeText={(t) =>inputHandler(t)}`
but that also doesnt solve it
Thanks!
Text is not displayed, because you react on changes, but not change state properly. onTextChanges callback return to you only text (as string), not as Event. If you need track Event you can use onChange callback.
But, I recommend to you write your logic as clean and simple as possible.
Firstly, you should separate inputHandler to independent text changes functions, because it easily to manage for now in your case. For example:
const onNameChanges = (text) => {
setInput(prev => ({
...prev,
fullName: text
}))
}
And then just assign it to props of your TextInput
<TextInput style={styles.input} placeholder="Name" value={input.fullName} onChangeText={onNameChanges}/>
That's it. You code works as expected. I prepared working example for you here
https://snack.expo.dev/BkQi-kXr-8

How to send data to another component in react-native

I want to pass data to another component but not like this.
return (
<View style = {{flex:1}}>
---> <LoginForm profile = {this.state.values}/> // I dont want to send like this
<Animated.View style={{ ...this.props.style, opacity: fadeAnim }} >
{this.props.children}
</Animated.View>
</View>
);
because if I do like this, this component includes LoginForm as well. and also I dont want to send with navigate. Because I dont want to open that component on screen. when I work in this screen I just want to send values to another component
You need to pass a function to mutate the state from LoginForm to this child component.
On LoginForm,
<View>
...
<ChildComponent changeProfile={(profile) => {
this.setState({
profile: profile
})
}}/>
</View>
then on this ChildComponent, call
this.props.changeProfile(this.state.values);
Or you can try a state management library too, like Redux or MobX. Personally, I prefer Redux.

Passing State to another Component in React Native

React Native Newbie here.
I have an (in my opinion) common use case here. I work with React Navigation and have 4 different Tabs. In the first Tab I have a FlatList from which I want to choose Favourites. These Favourites should be then listed in the other Tab. Nothing more so far.
The Problem I encounter is that I'm not figuring out how I can transmit the favourites variable declared in my state of the first tab, to the other Tab. Maybe the approach is completely wrong too..
First Tab/Screen:
import React, {Component} from 'react';
import { FlatList, Text, View, ScrollView, Image, TouchableHighlight} from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons'
export default class HomeScreen extends Component {
state = {
data: [],
favourites: []
};
//Function called on the click of the Heart Button, adding the List Element to the State
addFav = item => {
this.setState((prevState) => ({'favourites': prevState.favourites+item.title+' '}))
alert(item.title)
}
componentWillMount() {
this.fetchData();
}
//Fetching the data from the API
fetchData = async () => {
const response = await fetch("http://192.168.1.19:8080/v1/api/event");
const json = await response.json();
this.setState({ data: json});
};
render() {
return <FlatList
ItemSeparatorComponent={() =>
<View
style={{ height: 1, width: '100%', backgroundColor: 'lightgray' }}
/>
}
data={this.state.data}
keyExtractor={(item => item.title)}
renderItem={({ item }) =>
<ScrollView>
<Image style={{alignSelf:'stretch', width:undefined, height:undefined, flex : 1, borderRadius:10}} source = {require('../img/landscape.jpeg')}/>
<TouchableHighlight onPress={()=>this.openEvent(item)}>
<View style={{flex: 1, flexDirection:'row', padding: 5}}>
<View style={{flex: 1}}>
<Text style={{fontSize:15, textAlign:'center', padding: 2}}>{this.timeConverterMonth(item.time)}</Text>
<Text style={{fontSize:15, textAlign:'center', padding: 2}}>{this.timeConverterDay(item.time)}</Text>
</View>
<View style={{flex: 4}}>
<Text style={{fontSize:15, padding: 2}}>{item.title}</Text>
<Text style={{fontSize:10, padding: 2}}>{item.locShort}</Text>
</View>
//That's where the function is called
<TouchableHighlight
style={{flex: 2}}
onPress={() => this.addFav(item)}
>
<Icon name="ios-heart-empty" size={24} style={{alignSelf: 'center', padding: 10}}/>
</TouchableHighlight>
</View>
</TouchableHighlight>
//just checking the state
<Text>{this.state.favourites}</Text>
</ScrollView>}
/>;
}
}
Second Tab/Screen:
import React, {Component} from 'react';
import {Text} from 'react-native';
export default class FavouritesScreen extends Component {
constructor(props){
super(props)
}
render(){
//Here I want to display my favourites Array from the HomeScreen State
return <Text>{this.props.favourites}</Text>;
}
}
I am actually not wondering why it's not functioning, I just tried the props method by reading all the other articles but the Screens are not in Parent/Child relation.
So what I want to do would be in the Second Tab something like
HomeScreen.state.favourites
Thanks.
Your case is a very common one. One I faced was passing a 'shared state' between the application.
The components have a local state, which you can pass to child components via props (which you have mentioned).
The problem arises when you want to access that state in another component. The solution here is having a global state.
You may want to consider Redux for your application.
https://redux.js.org/introduction/getting-started
From the redux website:
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in
different environments (client, server, and native), and are easy to
test. On top of that, it provides a great developer experience, such
as live code editing combined with a time traveling debugger.
Essentially, you'll be getting a global state which can be accessed by all your application's components. This allows you to update states within one component and access them in another.
I will warn you, it's not the easiest thing to learn. When you first look at it - it's a bit daunting. But, as your application grows in complexity and you add more state - you'll be glad you used it.
The good news is, Redux is very well documented with React and React Native - so you should find lots of tutorials on how to integrate it into your current application.
Your usecase of having "globally" accessed state is where state management libraries come in. One good example is the libary Redux - in this case you could store the favourites under a piece of state called "HomeScreen" and map it and use it in any screen in the rest of the app.
Here is a good article about getting started with redux: https://blog.cloudboost.io/getting-started-with-react-native-and-redux-6cd4addeb29

Why React Native FlatList style not change with state

I have some tabs. I want to change the color of the selected tab. I created a state for selected tab index which will hold the tab ID. When Tab is pressed the selected state change to the pressed tab ID. I am comparing the selected state to tab ID. If both are equal then the selected tab will have some different style.
But when state changes and condition is true, the selected tab is not changing its state. Why change in state do not trigger the comparison in the style to update the style?
<FlatList
horizontal
data={this.state.drinkgroup}
showsHorizontalScrollIndicator={false}
renderItem={({item, index}) =>
{
return <Tab
item={item}
selected={this.state.selected}
changeSelected={
() => {
this.setState({selected: item.id}, function(){ console.log(this.state.selected, item.id)
console.log(this.state.selected==item.id)
})
}}
}
}
/>
export const Tab = ({item, selected, changeSelected}) => {
return (
<TouchableOpacity
style={[styles.tabStyle, (selected==item.id)? styles.tabSelectedStyle: null]}
onPress={changeSelected}
underlayColor='#fff'
>
<Text style={{color: '#f2f2f2', textAlign: 'center', fontSize: 15}}>{item.name}</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
tabStyle: {
backgroundColor: '#800080',
height: 32,
paddingRight: 15,
paddingLeft: 15
},
tabSelectedStyle: {
borderBottomColor: 'white',
borderBottomWidth: 3
}
})
By passing extraData={this.state} to FlatList we make sure FlatList itself will re-render when the state.selected changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.
<FlatList
data={this.props.data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
This is a PureComponent which means that it will not re-render if props remain shallow- equal.
Make sure that everything your renderItem function depends on is passed as a prop (e.g. extraData) that is not === after updates, otherwise your UI may not update on changes.
This includes the data prop and parent component state.
More Details :- FlatList
You need to provide extraData prop to the Flatlist, if you want it to re render its items. You can do it like extraData={this.state}.
By passing extraData={this.state} to FlatList we make sure FlatList itself will re-render when the state.selected changes. Without setting this extraData prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.
For further details you can visit official documentation here

Get TextInput value from different component

I have 2 react native components in my app, one is a toolbar that has a "Done" button, pressed when a user is done filling a form.
The other is the form itself from where I need to get the data.
When the user clicks "Done" I send a post request with the parameters, but I can't find a neat way to get the data.
What is best practice for this?
My toolbar:
<TopToolbar text='Upload new item'
navigator={this.props.navigator} state={this.state} donePage={'true'}/>
In the toolbar component I have the done button:
<TouchableHighlight style={styles.done} onPress={() =>{this.state.text=this.props.state.data.price}} underlayColor='#4b50f8'>
<Image source={require('./Images/Path 264.png')}/>
</TouchableHighlight>
and one of the text inputs is:
<TextInput placeholder='Price*' style={styles.text} onChangeText={(text) => { this.state.data.price = text }}></TextInput>
Use state. You need to bind the view to the model => (state). Please add your code for a better guide.
Each time that you press and new character need be saved in your state using onChangeText
Example:
class UselessTextInput extends Component {
constructor(props) {
super(props);
this.state = { text: 'Useless Placeholder' };
}
render() {
return (
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
);
}
}
When you press in Done button. The TextInput value will be stored in this.state.text
For more info: https://facebook.github.io/react-native/docs/textinput.html
I think your main problem is that you need to read more about the states in the react documentation
https://facebook.github.io/react-native/docs/state.html
When you needs set the state. You should use setState not this.state.data.price = text. The state is a object with multiple keys y your needs modify one internal key inside data you need modify all data key and replace it.
Example:
In your constructor declare
this.state = { data: {price: 10, name: xxxx} };
if need modify data you should do something like.
var dataM = this.state.data;
dataM.price = 200
this.setState({ data: dataM});