I am having trouble rendering my state. The initial value of my state is empty but when I press the button state change.
I want to see this change immediately but the state only renders when start to type something in my Textinput
This is my State:
constructor(props) {
super(props)
this.state = {
noteText: '',
userName:'',
}
}
I change state using onPress button
changeState(){
this.setState({userName:'Kevin'})
}
This is where I render my State
<View>
//I want to immediately render this.state.userName
<Text>{this.state.userName}</Text>
<TextInput
onChangeText={(noteText) => this.setState({noteText:noteText})}
value={this.state.noteText}
/>
</View>
My state won't render until I start to type something in my TextInput. Any idea how I can render immediately?
You have two ways here.
Set default state,
constructor(props) {
super(props)
this.state = {
noteText: '',
userName:'Kevin',
}
this.changeState = this.changeState.bind(this);
}
Or call changeState in componentDidMount,
componentDidMount(){
this.changeState(); //bind this to changeState in constructor
}
You can rather use inside bind your function inside your constructor, or use the arrow function.
constructor(props) {
this.changeState = this.changeState.bind(this);
}
or
changeState = () => {
this.setState({ userName: "Kevin" });
};
Check a simple snack: https://snack.expo.io/#abranhe/change-state
import React, { Component } from 'react';
import { Text, View, StyleSheet, Button } from 'react-native';
export default class App extends Component {
state = { userName: '' };
changeState = userName => {
this.setState({ userName });
};
render() {
return (
<View style={styles.container}>
<Text style={styles.username}>{this.state.userName}</Text>
<Button title="Abraham" onPress={() => this.changeState('Abraham')} />
<Button title="James" onPress={() => this.changeState('James')} />
<Button title="Mark" onPress={() => this.changeState('Mark')} />
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
username: {
alignSelf: 'center',
marginBottom: 20,
},
});
Related
My setState method is not invoked, while printing the value after setState always print the default value. I am using expo
import React from 'react';
import KeyboardShift from './KeyboardShift';
import FloatingLabel from 'react-native-floating-labels';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
focusDescriptionInput: false
}
}
render() {
return (
<SafeAreaView style={styles.container}>
<KeyboardShift>
{ () => (
<View>
<FloatingLabel
labelStyle={styles.labelInput}
inputStyle={styles.input}
style={styles.formInput}
returnKeyType={"next"}
onSubmitEditing={() => {
console.log(this.state.focusDescriptionInput)
context.setState({
focusDescriptionInput:true
})
console.log(this.state.focusDescriptionInput)
}}>
Email
</FloatingLabel>
<FloatingLabel
labelStyle={styles.labelInput}
inputStyle={styles.input}
style={styles.formInput}
focus={this.state.focusDescriptionInput}>
Email 2
</FloatingLabel>
</View>
)}
</KeyboardShift>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent:"center",
alignItems:"center",
marginTop: 50
},
textInput: {
fontSize: 16,
height: 40,
marginTop: 16
},
labelInput: {
color: '#673AB7',
},
formInput: {
borderBottomWidth: 1.5,
marginStart: 20,
marginEnd:20,
borderColor: '#333',
},
input: {
borderWidth: 0
}
});
Instead of context.setState, use this.setState.
And in your code if you want to print the value of the state after setState, it should be:
onSubmitEditing={() => {
console.log(this.state.focusDescriptionInput)
this.setState({
focusDescriptionInput:true
}, () => {
console.log(this.state.focusDescriptionInput)
})
}}>
Why? remember, setState is async. So, in this example I just used the callback function of setState. Hope this helps!
What you want is to focus. You don't need to change the state value. You can focus on reference values.
constructor(props) {
super(props);
// create a ref to save the textInput DOM element.
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// use the DOM API to explicitly focus text-type input elements.
this.textInput.current.focus();
}
<FloatingLabel
labelStyle={styles.labelInput}
inputStyle={styles.input}
style={styles.formInput}
returnKeyType={"next"}
onSubmitEditing={this.focusTextInput}>
Email
</FloatingLabel>
<FloatingLabel
ref={this.textInput}
labelStyle={styles.labelInput}
inputStyle={styles.input}
style={styles.formInput}
Email 2
</FloatingLabel>
Example
import React from 'react';
import { Platform, StyleSheet, Text, View,TextInput } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.textInput = React.createRef();
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
this.textInput.current.focus();
}
render() {
return (
<View style={styles.container}>
<TextInput
placeholder="testpalce"
style={{width:"90%",height:20,borderColor:"black",borderWidth:1}}
returnKeyType={"next"}
onSubmitEditing={this.focusTextInput}
/>
<TextInput
ref={this.textInput}
placeholder="next"
style={{width:"90%",height:20,borderColor:"black",borderWidth:1}}
returnKeyType={"next"}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#FFFFFF',
justifyContent:"center",
alignItems:"center"
}
});
I am trying to run a component method of another component. I am trying this using react ref. I am also following this link:
https://medium.freecodecamp.org/react-changing-state-of-child-component-from-parent-8ab547436271 But my structure is a bit more complicated.
List.js
class List extends Component {
constructor(){
super()
this.LoadCounterElement = React.createRef()
}
render(){
return(
<View>
<ItemGenerator />
<LoadCounter ref={this.LoadCounterElement}/>
</View>
)
}
}
function mapStateToProps(state) {
return {
counter: state.counter.counter
}
}
function mapDispatchToProps(dispatch) {
return {
increaseCounter: () => dispatch({ type: 'INCREASE_COUNTER' }),
decreaseCounter: () => dispatch({ type: 'DECREASE_COUNTER' }),
}
}
export default connect(mapStateToProps)(List);
ItemGenerator.js
class ItemGenerator extends Component {
render() {
return (
<ScrollView>
{
this.state.data.map((item, index) => {
return(<ItemList navigate={this.props.navigate} data={item} key={index}/>)
})
}
</ScrollView>
)
}
}
LoadCounter.js
class LoadCounter extends Component {
constructor(props) {
super(props)
this.state = {
count : 0,
}
}
componentDidMount() {
this._renderCount()
}
_renderCount = () => {
this.setState({count:this.props.counter})
}
render(){
return(
<View>
<Text>{this.state.count}</Text>
</View>
)
}
}
function mapStateToProps(state) {
return {
counter: state.counter.counter
}
}
export default connect(mapStateToProps)(withNavigation(LoadCounter));
ItemList.js
class ItemList extends Component {
render() {
return(
<View>
<TouchableOpacity onPress={() => {
this.props.increaseCounter()
this.LoadCounterElement.current._renderCount()
}}>
<Card containerStyle={{margin: 0}}>
<View style={{flex:1, flexDirection:'row', height:70, alignItems:'center', justifyContent:'space-between'}}>
<View style={{flexDirection:'row', alignItems:'center', width:'55%'}}>
<View style={{flexDirection:'column', marginLeft:10}}>
<Text style={{...}}>{this.props.data.name}</Text>
</View>
</View>
</View>
</Card>
</TouchableOpacity>
</View>
)
}
}
function mapDispatchToProps(dispatch) {
return {
increaseCounter: () => dispatch({ type: 'INCREASE_COUNTER' }),
decreaseCounter: () => dispatch({ type: 'DECREASE_COUNTER' }),
}
}
export default connect(mapStateToProps)(ItemList);
counterReducer.js
const initialState = {
counter: 1
}
const counterReducer = (state = initialState, action) => {
switch (action.type) {
case 'INCREASE_COUNTER':
return { counter: state.counter + 1 }
case 'DECREASE_COUNTER':
return { counter: state.counter - 1 }
}
return state
}
export default counterReducer;
As you can see in ItemLiist Component, i am trying to run _renderCount method which is in Component LoadCounter. But its not working. Kindly guide what i am missing?
The problem here is that you have some data in child component that should be reflected in a parent component. I would recommend that you move the shared state in the parent component or to the reducer state.
It is odd that you are using an action creator to increment/decrement counts - which I am thinking that updates some reducer state. If this is the case, why store that state in the local component state again ? You could just read the counter state from the reducer in your parent component.
Parent.js
class Parent extends React.Component {
render() {
return (
<div>
<span>{this.props.count}</span>
</div>
);
}
}
const mapStateToProps = state => ({
count: state.yourCountReducer.count,
});
export default connect(mapStateToProps)(Parent);
Child.js
class Child extends React.Component {
render() {
return (
<div>
<button onClick={() => this.props.increaseCounter()}>+</button>
<button onClick={() => this.props.decreaseCounter()}>-</button>
</div>
);
}
}
const mapDispatchToProps = dispatch => ({
increaseCounter: () => dispatch({ type: 'INCREASE_COUNTER' }),
decreaseCounter: () => dispatch({ type: 'DECREASE_COUNTER' }),
});
export default connect(null, mapDispatchToProps)(Child);
This way, the parent component will show the updated counter state when the child component updates the count. From your sample code, I am not sure if there is any good reason to store a shared reducer state in any component's local state.
I'm making a modal that will popup when the user clicks a flatlist button or items, and there the user will see the details about the item he/she clicks. Basically, I want to pass the items of flatlist to modal.
I'm actually done with the popup of the modal, now I have to show the details like menu description and menu price. I've found a post here in stackoverflow and I follow everything in there but I am having an error regarding with an " id ", and I can't figure out how to fix it.
Here is my code
Details.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl, Dimensions, Modal, TextInput, TouchableWithoutFeedback, Keyboard
} from 'react-native';
import AddModal from '../Modal/AddModal';
var screen = Dimensions.get('window');
const DismissKeyboard = ({ children }) => (
<TouchableWithoutFeedback onPress = {() => Keyboard.dismiss()}>
{children}
</TouchableWithoutFeedback>
);
export default class Details extends Component {
static navigationOptions = {
title: ''
};
constructor()
{
super ()
this.state = {
data: [],
showModal: false,
id: null,
}
}
fetchData = async() => {
const { params } = this.props.navigation.state;
const response_Cat = await fetch('http://192.168.254.101:3307/categories/' + params.id);
const category_Cat = await response_Cat.json();
this.setState({data: category_Cat});
};
componentDidMount() {
this.fetchData();
};
_onRefresh() {
this.setState({ refreshing: true });
this.fetchData().then(() => {
this.setState({ refreshing: false })
});
};
_onPressItem(id) {
this.setState({
modalVisible: true,
id: id
});
}
_renderItem = ({item}) => {
return (
<TouchableHighlight
id = { item.menu_desc }
onPress = { this._onPressItem(item.menu_desc) }
>
<View>
<Text>{ this.state.id }</Text>
</View>
</TouchableHighlight>
)
};
render() {
const { params } = this.props.navigation.state;
return (
<View style = { styles.container }>
<AddModal
modalVisible = { this.state.modalVisible }
setModalVisible = { (vis) => { this.setModalVisible(vis) }}
id = { this.state.id }
/>
<FlatList
data = { this.state.data }
renderItem = { this._renderItem }
keyExtractor={(item, index) => index}
/*refreshControl = {
<RefreshControl
refreshing = { this.state.refreshing }
onRefresh = { this._onRefresh.bind(this) }
/>
}*/
/>
</View>
);
}
}
const styles = StyleSheet.create({
...
})
//AppRegistry.registerComponent('Details', () => Details);
AddModal.js
import React, {Component} from 'react';
import {Text, TouchableHighlight, View,
StyleSheet, Platform, FlatList, AppRegistry,
TouchableOpacity, RefreshControl, Dimensions, TextInput, Modal
} from 'react-native';
export default class AddModal extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
id: null
};
}
componentWillReceiveProps(nextProps) {
this.setState({
showModal: nextProps.showModal,
id: nextProps.id,
})
}
render() {
return (
<Modal
animationType="slide"
transparent={ true }
visible={ this.state.modalVisible }
onRequestClose={() => { this.props.setModalVisible(false) }}>
<View>
<View>
<Text>{ this.state.id }</Text>
<TouchableHighlight
onPress = {() => { this.props.setModalVisible(false) }}
>
<Text>Hide Modal</Text>
</TouchableHighlight>
</View>
</View>
</Modal>
)
}
}
Just wanted to pointout an issue in your code (not related to 'id' error, id error already answer by digit). In the renderItem function, you are calling onPress = { this._onPressItem(item.menu_desc) }, it should be changed to
onPress = { () => this._onPressItem(item.menu_desc) }
I guess, you will call the onPressItem when user click on list item.
EDIT:
I have made a couple of changes to make your code working. Here are the changes.
In your AppModal.js, you are setting modal visibility in showModal: nextProps.showModal , but in the <Modal ...> you have set visible
= { this.state.modalVisible }. Also in Details.js you have written <AddModal modalVisible ...>.
First I changed showModal to modalVisible in Details.js and in AppModal.js.
Details.js
constructor()
{
super ()
this.state = {
data: [],
modalVisible: false,
id: null,
}
}
Then I changed _onPressItem(id) to _onPressItem = (id)
Made changes in renderItem as
<TouchableHighlight
id = { item.enName }
onPress = { () => this._onPressItem(item.enName) }
>
in render function I have set modal visibility as
<AddModal
...
setModalVisible = { (vis) => { this.setState({
modalVisible: vis
})
}}
...
/>
AppModal.js
Changed showModal to modalVisible
constructor(props) {
super(props);
this.state = {
modalVisible: props.modalVisible,
d: null
};
}
componentWillReceiveProps(nextProps) {
this.setState({
modalVisible: nextProps.modalVisible,
id: nextProps.id,
})
}
In the constructor, I have added modalVisible: props.modalVisible.
Hope this will help!
I guess item.menu_desc is an id of each item so it must be {item.menu_desc} not {id}. Change it like below
_renderItem = ({item}) => {
return (
<TouchableHighlight
id = { item.menu_desc }
onPress = { this._onPressItem(item.menu_desc) }
>
<View>
<Text>{ item.menu_desc }</Text>
</View>
</TouchableHighlight>
)
};
I updated the code to reflect Denis' solution. However, react is now no longer responding to commands sent from the node server
export default class Display extends Component {
constructor(props){
super(props);
this.state = {
ren: "",
action: "background",
media: "white",
backgroundColor: 'white',
uri: "https://www.tomswallpapers.com/pic/201503/720x1280/tomswallpapers.com-17932.jpg"
};
}
componentDidMount(){
this.startSocketIO();
}
componentWillUnmount(){
socket.off(Socket.EVENT_CONNECT);
}
startSocketIO(){
socket.on('function_received', func_var => {
let command = func_var.split(" ");
this.setState({action: command[0]});
this.setState({media: command[1]});
console.log(this.state.action);
console.log(this.state.media);
switch(this.state.action){
case 'image':
this.setState({ uri: this.state.media});
console.log(this.state.uri);
case 'background':
this.setState({ backgroundColor: this.state.media});
console.log(this.state.backgroundColor);
default:
console.log(this.state.backgroundColor);
// return (<View style={{backgroundColor: this.state.backgroundColor, flex: 1}} />);
}
});
}
render(){
return (
null
);
}
}
I'm currently working on a basic react native app that displays images received in uri format from a node server and changes the background color. Separately, both of my implementations work. (See the BackGround and ImageServer components) I'm now attempting to combine the functionality of both components into one component named display. So far my current code looks like it should work without issue however after sending a command to the device via socket.io it appears that the render doesn't go any further since my console logs stop populating after a test. I'm not sure if there is an issue with the setup of the switch statement or if I'm somehow causing a race condition. Any insight would be greatly appreciated!
import React, { Component } from 'react';
import {Image, Text, StyleSheet, Button, View, Dimensions, Vibration} from 'react-native';
const io = require('socket.io-client');
//change this to your public ip "google what is my ip address"
//This will be modified in the future to grab the ip address being used by
//the node server
let server = 'redacted';
let socket = io(server, {
transports: ['websocket']
});
export default class Display extends Component {
constructor(props){
super(props);
this.state = {
action: "background",
media: "white",
backgroundColor: 'white',
uri: "https://www.tomswallpapers.com/pic/201503/720x1280/tomswallpapers.com-17932.jpg"
};
}
render(){
socket.on('function_received', func_var => {
var command = func_var.split(" ");
this.setState({action: command[0]});
this.setState({media: command[1]});
});
console.log(this.state.action);
console.log(this.state.media);
switch(this.state.action){
case 'image':
this.setState({ uri: this.state.media});
return (
<Image
source={{uri: this.state.uri}}
style={styles.fullscreen} />
);
case 'background':
this.setState({ backgroundColor: this.state.media});
return (<View style={{backgroundColor: this.state.backgroundColor, flex: 1}} />);
default:
return (<View style={{backgroundColor: this.state.backgroundColor, flex: 1}} />);
}
}
}
export class BackGround extends Component {
constructor(props){
super(props);
this.state = {
backgroundColor: 'black'
};
}
render(){
socket.on('function_received', func_var => {
this.setState({ backgroundColor: func_var});
});
return (
<View style={{backgroundColor: this.state.backgroundColor, flex: 1}} />
);
}
}
export class ImageServer extends Component {
constructor(props){
super(props);
this.state = {
uri: "https://www.tomswallpapers.com/pic/201503/720x1280/tomswallpapers.com-17932.jpg"
};
}
render() {
socket.on('function_received', func_var => {
//Vibration.vibrate([0, 500, 200, 500,200,500,200,500,200,500,200,500,200], false);
this.setState({ uri: func_var});
});
return(
<Image
source={{uri: this.state.uri}}
style={styles.fullscreen}
/>
);
}
}
You code should like this
componentDidMount() {
this.startSocketIO();
}
startSocketIO() {
socket.on('some_method', (response) => {
this.setState({ key: response.some_value })
});
}
componentWillUnmount() {
// unsubscribe socket.io here !important
}
render() {
return (
// JSX
);
}
I'm an iOS developer currently working on an experimental React Native app.
I have the following code which shows a button and sample text on the screen.
import React from 'react';
import { StyleSheet, Text, View , Button } from 'react-native';
export default class App extends React.Component {
constructor() {
super();
this.state = {sampleText: 'Initial Text'};
}
changeTextValue = () => {
this.setState({sampleText: 'Changed Text'});
}
_onPressButton() {
<Text onPress = {this.changeTextValue}>
{this.state.sampleText}
</Text>
}
render() {
return (
<View style={styles.container}>
<Text onPress = {this.changeTextValue}>
{this.state.sampleText}
</Text>
<View style={styles.buttonContainer}>
<Button
onPress={this._onPressButton}
title="Change Text!"
color="#00ced1"
/>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f5deb3',
alignItems: 'center',
justifyContent: 'center',
},
buttonContainer: {}
});
The above code displays text and a button.
However when I click the button, the app crashes instead of showing the new text which is to be shown.
I'm new to React Native, kindly guide me on how to solve the error.
You could use a state to keep your default text and then on press we update the state.
import React, { Component } from 'react'
import { View, Text, Button } from 'react-native'
export default class App extends Component {
state = {
textValue: 'Change me'
}
onPress = () => {
this.setState({
textValue: 'THE NEW TEXT GOES HERE'
})
}
render() {
return (
<View style={{paddingTop: 25}}>
<Text>{this.state.textValue}</Text>
<Button title="Change Text" onPress={this.onPress} />
</View>
)
}
}
You can use state for dynamically change the text
import React, {Component} from 'react';
import {Text, Button, View} from 'react-native';
export default class App extends Component{
constructor(){
super();
this.state = {
textValue: 'Temporary text'
}
this.onPressButton= this.onPressButton.bind(this);
}
onPressButton() {
this.setState({
textValue: 'Text has been changed'
})
}
render(){
return(
<View style={{paddingTop: 20}}>
<Text style={{color: 'red',fontSize:20}}> {this.state.textValue} </Text>
<Button title= 'Change Text' onPress= {this.onPressButton}/>
</View>
);
}
}
With hooks:
import React, {useState} from "react";
import {Button, Text, View} from "react-native";
const App = () => {
const [text, setText] = useState("Initial text");
const onPressHandler = event => setText("Changed text");
return (
<View>
<Text>{text}</Text>
<Button title="Change Text" onPress={onPressHandler} />
</View>
);
};
You better make sure what _onPressButton() is doing. You can simply setState() in this function and do nothing else, which can help you solve the problem. If you want to render something new, you have to add return() and wrap up Text.
You can use this approach for updating a value on click of a button
class App extends React.Component {
constructor() {
super();
this.state = { val: 0 }
this.update = this.update.bind(this)
}
update() {
this.setState({ val: this.state.val + 1 })
}
render() {
console.log('render');
return <button onClick={this.update}>{this.state.val}</button>
}
}
It's because your onPress function is a little weird, you want to invoke an action on press, not have jsx elements. Your changeTextValue is what should be passed into your button's onPress.
Set my text in state method then update state in pressed button, then set in text like this:
<Text>
{this.state.myText}
</Text>
import React, { useState } from "react";
import { View, Text } from "react-native";
const App = () => {
const [value, setValue] = useState("Mohd Sher Khan");
const hellod = () => {
setValue("value changed");
};
return (
<View>
<Text onPress={hellod}>{value}</Text>
</View>
);
};
export default App;