Cannot update during existing state - react-native

Index.js
I try do launch screen.
export default class LaunchScreen extends Component{
constructor(props){
super(props);
this.state= {
loaded:false
}
}
componentWillMount(){
Thread.load(v => this.setState({loaded:true}));
}
render(){
const { navigate } = this.props.navigation;
return(
<View style={styles.container}>
{this.state.loaded ? navigate("Form")
:
<View style={styles.imageContent}>
<Image style={styles.image}
source={require('../images/launch_icon.png')}/>
</View>
}
</View>
)}}
export default class thread{
static load(cb){
setTimeout(cb,3000);
}
}
when I use these codes I get the warning "can not update during an existing state transition". How to fix it?

You're trying to navigate inside a return, try to change your render code to this:
render(){
const { navigate } = this.props.navigation;
if(this.state.loaded) navigate("Form")
return(
<View style={styles.container}>
<View style={styles.imageContent}>
<Image style={styles.image}
source={require('../images/launch_icon.png')}/>
</View>
</View>
)
}
EDIT: But you should probably do the navigation part inside a shouldComponentUpdate() checking if the nextState.loaded is different from your this.state.loaded and is true, like:
shouldComponentUpdate(nextProps, nextState){
if((nextState.loaded!=this.state.loaded)&&nextState.loaded){
navigate("Form")
return true
}
return false
}

I see a couple problems, but I don't think these are your main problems.
You can only have one default export, so if both classes are actually in a single file, remove the "default" from the thread class.
Pretty sure all class names must begin with a capital letter in React, so change "thread" to "Thread"
But I think your actual problem is that you're calling navigate('Form') directly from within the render. Try adding a handleNavigation class method and calling this.handleNavigation there instead. So you'd be left with something like this...
export default class LaunchScreen extends Component {
state = {
loaded: false
}
componentWillMount() {
Thread.load( () => this.setState({loaded: true}));
}
handleNavigation = () => {
this.props.navigation('Form');
}
render() {
return (
<View style={styles.container}>
{
this.state.loaded
? this.handleNavigation
: <View style={styles.imageContent}>
<Image style={styles.image}
source={require('../images/launch_icon.png')}/>
</View>
}
</View>
);
}
}
export class Thread {
static load(cb){
setTimeout(cb,3000);
}
}

Related

How can I hide/show components by touching not button but screen on React Native?

I'm learning React Native for the first time. I want to implement a function to show/hide the component by touching the screen, not a specific button.
(Please check the attached file for the example image.)
enter image description here
In this code, I've tried to make a function. if I touch the screen (<View style={style.center}>, then show/hide the renderChatGroup() and renderListMessages() included in <View style={style.footer}>. The source code is below.
In my code, it works. However, the two <View> tag is not parallel. the footer view is center View's child.
I want to make them parallel. but I couldn't find the contents about controlling another <View> tag, not a child. In this code, I used setState, then I couldn't control another the below <View>.
Of course, I tried Fragment tag, but it didn't render anything.
How could I do implement this function? Please help me!
export default class Streamer extends React.Component {
constructor(props) {
super(props);
this.state = {
isVisibleFooter: true,
};
}
renderChatGroup = () => {
const { isVisibleFooter } = this.state;
if (isVisibleFooter) {
return (
<ChatInputGroup
onPressHeart={this.onPressHeart}
onPressSend={this.onPressSend}
onFocus={this.onFocusChatGroup}
onEndEditing={this.onEndEditing}
/>
);
}
return null;
};
onPressVisible = () => {
const { isVisibleFooter } = this.state;
this.setState(() => ({ isVisibleFooter: !isVisibleFooter }));
};
render() {
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={styles.contentWrapper}>
<View style={styles.header} />
<TouchableWithoutFeedback onPress={this.onPressVisible}>
<View style={styles.center}>
<View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>
</View>
</TouchableWithoutFeedback>
</SafeAreaView>
</SafeAreaView>
);
}
}
Firstly I would highly recommend you use react native with functional components and React Hooks as they alternative will soon will be deprecated.
Since onPress is not available on the View Component, you would need to replace it with TouchableWithoutFeedback as you have already done in your code.
For Showing/Hiding a view you would need to use a conditional operator.
export default class Streamer extends React.Component {
constructor(props) {
super(props);
this.state = {
isVisibleFooter: true,
};
}
renderChatGroup = () => {
const { isVisibleFooter } = this.state;
if (isVisibleFooter) {
return (
<ChatInputGroup
onPressHeart={this.onPressHeart}
onPressSend={this.onPressSend}
onFocus={this.onFocusChatGroup}
onEndEditing={this.onEndEditing}
/>
);
}
return null;
};
onPressVisible = () => {
this.setState(() => ({ isVisibleFooter: !isVisibleFooter }));
const { isVisibleFooter } = this.state;
};
render() {
return (
<SafeAreaView style={styles.container}>
<SafeAreaView style={styles.contentWrapper}>
<View style={styles.header} />
<TouchableWithoutFeedback onPress={this.onPressVisible}>
<View style={styles.center}>
{isVisibleFooter && <View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>}
</View>
</TouchableWithoutFeedback>
</SafeAreaView>
</SafeAreaView>
);
}
}
Here you can see i have replaced
<View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>
with
{isFooterVisible && <View style={styles.footer}>
{this.renderChatGroup()}
{this.renderListMessages()}
</View>}
stating that to only display the Footer View when
const isFooterVisible = true;

onPress is called automatically while using NetInfo - react native

NetInfo is used to check the connection & theres a checkNetwork function called in onPress of TouchableOpacity. When the button is clicked once, the checkNetwork
function is called automatically multiple times without tapping the button when the network connection is lost and vice versa.
Please have a look at the code here:
Please have a look at the video
export default class App extends React.Component {
checkNetwork = () => {
NetInfo.addEventListener((state) => {
if (state.isConnected) {
alert('isConnected');
} else {
alert('not connected');
}
});
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity
activeOpacity={0.8}
onPress={()=> this.checkNetwork()}>
<Text>Check here</Text>
</TouchableOpacity>
</View>
);
}
}
You should not declare event listener inside of the click itself,
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {alert: ''};
}
componentDidMount() {
NetInfo.addEventListener((state) => this.setState({ alert: state.isConnected ? 'isConnected' : 'not connected'})
}
checkNetwork = () => alert(this.state.alert)
render() {
return (
<View style={styles.container}>
<TouchableOpacity
activeOpacity={0.8}
onPress={()=> this.checkNetwork()}>
<Text>Check here</Text>
</TouchableOpacity>
</View>
);
}
}
though in your case event listener isn't exactly the fit logic for UI behavior of pressing button, so I think you might wanna use useNetInfo
import {useNetInfo} from "#react-native-community/netinfo";
class App extends React.Component {
checkNetwork = () => {
if (this.props.netInfo.isConnected) {
alert('isConnected');
} else {
alert('not connected');
}
});
};
...rest render...
}
export default () => <App netInfo={useNetInfo()} />

unable to update parent from child

The included code is almost running. I'm trying to restart the count where it left off when I toggle the device. I'm getting the following error message:
Warning: Functions are not valid as a React child. This may happen if you
return a Component instead of <Component /> from render. Or maybe you meant
to call this function rather than return it.
here's what I was attempting:
1)pass as this.props.count class App this.state.count (this creates the starting point of the counter
2) pass a callback function from APP to COUNTER that will update APP.state.count (I do this inside of COUNTERS Inc method)
NOTE: it's a little tricky to get ignorewarnings working if you don't have the right dependencies installed. lines 3, 4 and 5 can be deleted
import React from 'react';
import {Button, StyleSheet, Text, View } from 'react-native';
import ignoreWarnings from 'react-native-ignore-warnings';
ignoreWarnings(['Warning: componentWillMount is deprecated',
'Warning: componentWillReceiveProps is deprecated'])
class Count extends React.Component {
shouldComponentUpdate(nextProps,nextState){
if(nextProps.count % 2 === 0)return true
else return true
}
render(){
return(
<Text style={styles.count}>{this.props.count}</Text>
)
}
}
class Counter extends React.Component {
constructor(props){
super(props)
this.state={
count: this.props.count,
}
console.log(this)
}
componentDidMount(){
this.interval=setInterval(this.inc,1000)
}
componentWillUnmount(){
clearInterval(this.interval)
}
inc=()=>{
//console.log(thisate)
this.setState(prevState =>({
count: prevState.count + 1,
}))
this.props.resetCount(this.state.count)
}
render() {
return (
<View>
<Count count={this.state.count}/>
</View>
);
}
}
export default class App extends React.Component {
constructor(){
super()
this.state={
show:true,
count:0,
}
}
toggle=()=> this.setState(prevState => ({
show: !prevState.show
}))
resetCounter(count){
this.setState({count: Count})
}
render(){
console.log(this.state)
if(this.state.show){
return(
<View style={styles.container}>
<Button title='toggle' onPress={this.toggle}/>
<Counter
count={this.state.count}
resetCount={(count)=>{this.resetCounter(count)}} />
</View>
)
}else{
return(
<View style={styles.container}>
<View style={styles.container}>
<Button style={styles.count} title='toggle' onPress={this.toggle}/>
<Text style={styles.count}> </Text>
</View>
</View>
)
}
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'lightgrey',
alignItems: 'center',
justifyContent: 'center',
},
count:{
fontSize:48
}
});
First problem i see, and i think the warning come from here, is you resetCounter function. You pass "Count" (a component) to the state. I think you would like to pass the argument : count. You could do it simply like this so there is not mistake :
resetCounter(count){
this.setState({count})
}
Second thing is your callback way. You should do it like this :
export default class App extends React.Component {
constructor(){
super()
this.resetCounter = this.resetCounter.bind(this);
this.state={
show:true,
count:0,
}
}
resetCounter(count){
this.setState({count: Count})
}
render(){
...
return(
<View style={styles.container}>
<Button title='toggle' onPress={this.toggle}/>
<Counter
count={this.state.count}
resetCount={this.resetCounter} />
</View>
...
)
}
}
It's a lot better for performance and for reading.
Hope it help !
just a typo! yureka.
resetCounter(count){
this.setState({count: Count})
}
needs to be:
resetCounter(count){
this.setState({count: count})
}

render is not calling on state change

export default class TopMiddleLoadingView extends React.Component{
size = 66;
constructor(props) {
super(props);
this.state = {
fill : 99,
timeLeft : props.timeLeft
}
}
onPress(){
this.setState = {
...this.state, fill:10
}
}
componentWillUpdate(nextProps, nextState) {
alert("componentWillUpdate");
}
render(){
alert("render")
return(
<View style={{width:this.size, height:this.size}}>
<View style={[styles.absoluteCenter,{zIndex:999}]}>
<Thumbnail source={Images.seaImg}></Thumbnail>
</View>
<Text>{this.state.fill}</Text>
<Button
style={{width:50,height:50,backgroundColor:"red",position:"absolute",zIndex:999}}
onPress={this.onPress}
></Button>
</View>
);
}
}
on button press, onPress function is clicked, and change the state of the component, but the render function is not calling.
I am very new to react native. Any idea?
You aren't changing the state either let alone re render. And if you want to re render then you should change state using setState() method. Also, you need to refresh you javascript this knowledge
export default class TopMiddleLoadingView extends React.Component{
size = 66;
constructor(props) {
super(props);
this.state = {
fill : 99,
timeLeft : props.timeLeft
}
}
onPress = () => {
this.setState({fill:10})
}
componentWillUpdate(nextProps, nextState) {
alert("componentWillUpdate");
}
render(){
alert("render")
return(
<View style={{width:this.size, height:this.size}}>
<View style={[styles.absoluteCenter,{zIndex:999}]}>
<Thumbnail source={Images.seaImg}></Thumbnail>
</View>
<Text>{this.state.fill}</Text>
<Button
style={{width:50,height:50,backgroundColor:"red",position:"absolute",zIndex:999}}
onPress={this.onPress}
></Button>
</View>
);
}
}
Render method is called whenever there is change in state of that component. You should use this.setState({...this.state, fill:10} for updating state of the component. This must cause render function to fire again, if there is not any other logic written inside shouldComponentUpdate() for conditional rendering.
Hope this helps. Also check out,
What the difference of this.state and this.setstate in ReactJS?

Infinite loop with React-Redux and Navigation Experimental

I have an infinite loop that seems to be occurring when I use react-redux. I use Navigation Experimental which loads connectRouteScreen as the scene to be rendered through NavigationCardStack. I'm using RN 0.30. But also could reproduce this in 0.31-rc.0
[...]
Use Navigation Experimental to transition and load connectRouteScreen as a Scene
export default function connectRouteScreen(Scene, sceneProps){
class RouteScreen extends React.Component{
[...]
render() {
const { navigator, pathVariables } = this.props;
return (
<View style={styles.container}>
<Scene
navigator={navigator}
{...pathVariables.toJS()}
/>
</View>);
}
}
RouteScreen.propTypes = {...RouteScreenPropTypes};
const routeScreenProperties = extractSceneRendererProps(sceneProps);
/*return <Scene
navigator={routeScreenProperties.navigator}
{...routeScreenProperties.pathVariables.toJS()}
/>;
*/
return <RouteScreen
{...routeScreenProperties}
/>;
}
LoadingScreen is loaded as "Scene".
#connect(
() => {return {}},
(dispatch) => {
return {
loginActions: bindActionCreators(loginActions, dispatch),
}
})
export default class LoadingScreen extends React.Component {
constructor(props){
super(props);
}
shouldComponentUpdate(nextProps){
return false;
}
componentDidMount(){
const { navigator } = this.props;
this.props.loginActions.executeLoginFlow();
}
render() {
const Animatable = require('react-native-animatable');
return (
<Animatable.View
animation="pulse"
easing="ease-out"
iterationCount="infinite"
style={localStyle.container}>
<Icon name="logo" style={localStyle.iconStyle} size={150}/>
</Animatable.View>
);
}
};
So, If I return the Scene directly instead of RouteScreen, no problem.
If I remove the #connect syntax and escape this.props.loginActions..., no problem.
If I return RouteScreen and remove everything it does and just return the Scene => infinite loop.
Does anybody have any suggestions how to deal with this?