0

I'm new to react-native and I'm trying to build an application connected to a ruby on rails backend.

I have an index view in which I retrieve a list of lunches, I would like that when I click on one of them, I go to that presentation. so I created a specific view in which I redo an api call to retrieve the lunch data and then I display this one. The problem is that it tries to read the data first and then it makes the api call after that while the method is in a componentWillMount() and the api call is done after that because I see it in the logs.

INDEX.js

import React from 'react';
import { View, Text, Image, StyleSheet, ScrollView, TouchableHighlight } from 'react-native'
import { Card, ListItem, Button } from 'react-native-elements'
import { Actions } from 'react-native-router-flux';

export default class IndexLunches extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      lunches: []
    };
    this.show = this.show.bind(this)
  }
  fetchLunches() {
    fetch('http://192.168.1.24:3000/api/v1/lunches', {
      method: 'GET',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        }
    })
    .then((response) => {
      if (response.ok) {
        console.log('RESPONSE OK : GET LUNCHES')
        var lunches = JSON.parse(response._bodyText);
        var headers = response.headers
        console.log(lunches)
        console.log(headers)
        this.setState({lunches: lunches})

      } else {
        alert("Erreur pendant la réceptions des lunchs voir les logs")
        console.log(response)
      }

    })
    .catch(function(error) {
      console.log('There has been a problem with your fetch operation: ' + error.message);
      // ADD THIS THROW error
        throw error;
      })
    .done();

  }

  show(id) {
    Actions.show_lunch({lunch_id: id})
  }

  lunchCard() {
    lunches = this.state.lunches
    return lunches.map((lunch, i) => {
      return(
        <TouchableHighlight key={i} onPress={() => this.show(lunch.id)}>
          <View 
            // key={i}
            // Error here because react auto execute onPress on load
            >
            <Image
              style={{flex: 1, height: 150}}
              source={{ uri: lunch.photos[0].url }}
            />
            <Text>Titre du lunch : {lunch.title}</Text>
            <View>
              <Text>id : {lunch.id}</Text>
            </View>
        </View>
        </TouchableHighlight>
      );
    });
  }
  // Its called before render component
  componentWillMount() {
    this.fetchLunches();
  }
  render () {
    return (
      <ScrollView>
        <Text style={styles.title} > Liste des lunchs </Text>
        <View>
          { this.lunchCard() }
        </View>
      </ScrollView>
    )
  }
}

const styles = StyleSheet.create({
  title: {
    color: "#0000FF",
    fontSize: 16,
    marginBottom: 20,
  },
  text: {

  }
})

Show.js

import React from 'react';
import { View, Text, Image, StyleSheet, ScrollView } from 'react-native'
import { Card, ListItem, Button } from 'react-native-elements'

export default class ShowLunch extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      lunch: {},
      lunch_id: this.props.navigation.state.params.lunch_id
    };
  }
  fetchLunch() {
    let id = this.state.lunch_id
    fetch(`http://192.168.1.24:3000/api/v1/lunches/${id}`, {
      method: 'GET',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
        }
    })
    .then((response) => {
      if (response.ok) {
        console.log(`RESPONSE OK : GET LUNCH, ID: ${id}` )
        var lunch = JSON.parse(response._bodyText);
        var headers = response.headers
        console.log(lunch.lunch)
        console.log(headers)
        this.setState({lunch: lunch.lunch})

      } else {
        alert("Erreur pendant la réceptions du lunch voir les logs")
        console.log(response)
      }

    })
    .catch(function(error) {
      console.log('There has been a problem with your fetch operation: ' + error.message);
      // ADD THIS THROW error
        throw error;
      })
    .done();

  }

  lunchView() {
    lunch = this.state.lunch
    console.log("ENTER IN LUNCH VIEW")
    console.log(lunch)
    return(
        <View key="lunch">
          <Image
            style={{flex: 1, height: 150}}
            source={{ uri: lunch.photos[0].url }}
          />
          <Text>Titre du lunch : {lunch.title}</Text>
          <View>
            <Text>id : {lunch.id}</Text>
          </View>
      </View>
    );
  }
  // Called before render component
  componentWillMount() {
    this.fetchLunch();
  }
  render () {
    return (
      <ScrollView>
        <Text style={styles.title} >Lunch : </Text>
        <View>
          { this.lunchView() }
        </View>
      </ScrollView>
    )
  }
}

const styles = StyleSheet.create({
  title: {
    color: "#0000FF",
    fontSize: 16,
    marginBottom: 20,
  },
  text: {

  }
})

Console.log

LOGIN SUCCESSFULL
Login.js:62 VALIDATE TOKEN SUCCESSFULL
Login.js:63 Response {type: "default", status: 200, ok: true, statusText: undefined, headers: Headers, …}
Login.js:65 {…}
IndexLunches.js:24 RESPONSE OK : GET LUNCHES
IndexLunches.js:27 (6) [{…}, {…}, {…}, {…}, {…}, {…}]
IndexLunches.js:28 Headers {map: {…}}
ShowLunch.js:48 ENTER IN LUNCH VIEW
ShowLunch.js:49 {}
ExceptionsManager.js:65 TypeError: Cannot read property '0' of undefined

This error is located at:
    in ShowLunch (at navigationStore.js:319)
    in Wrapped (at SceneView.js:31)
    in SceneView (at CardStack.js:412)
    in RCTView (at View.js:113)
    in View (at CardStack.js:411)
    in RCTView (at View.js:113)
    in View (at CardStack.js:410)
    in RCTView (at View.js:113)
    in View (at createAnimatedComponent.js:134)
    in AnimatedComponent (at Card.js:26)
    in Card (at PointerEventsContainer.js:55)
    in Container (at CardStack.js:454)
    in RCTView (at View.js:113)
    in View (at CardStack.js:383)
    in RCTView (at View.js:113)
    in View (at CardStack.js:382)
    in CardStack (at CardStackTransitioner.js:97)
    in RCTView (at View.js:113)
    in View (at Transitioner.js:192)
    in Transitioner (at CardStackTransitioner.js:49)
    in CardStackTransitioner (at StackNavigator.js:60)
    in Unknown (at createNavigator.js:52)
    in Navigator (at createNavigationContainer.js:210)
    in NavigationContainer (at Router.js:70)
    in App (at Router.js:91)
    in Router (at LunchRouter.js:31)
    in LunchRouter (at App.js:16)
    in RCTView (at View.js:113)
    in View (at App.js:14)
    in App (created by AwakeInDevApp)
    in RCTView (at View.js:113)
    in View (created by AwakeInDevApp)
    in AwakeInDevApp (at registerRootComponent.js:34)
    in RootErrorBoundary (at registerRootComponent.js:33)
    in ExpoRootComponent (at renderApplication.js:35)
    in RCTView (at View.js:113)
    in View (at AppContainer.js:102)
    in RCTView (at View.js:113)
    in View (at AppContainer.js:122)
    in AppContainer (at renderApplication.js:34)
handleException @ ExceptionsManager.js:65
ReactNativeFiberErrorDialog @ ReactNativeFiber-dev.js:231
logCapturedError @ ReactNativeFiber-dev.js:19
captureError @ ReactNativeFiber-dev.js:2649
performWork @ ReactNativeFiber-dev.js:2601
batchedUpdates @ ReactNativeFiber-dev.js:2756
batchedUpdates @ ReactNativeFiber-dev.js:202
batchedUpdatesWithControlledComponents @ ReactNativeFiber-dev.js:209
_receiveRootNodeIDEvent @ ReactNativeFiber-dev.js:3559
receiveTouches @ ReactNativeFiber-dev.js:3572
__callFunction @ MessageQueue.js:302
(anonymous) @ MessageQueue.js:116
__guard @ MessageQueue.js:265
callFunctionReturnFlushedQueue @ MessageQueue.js:115
(anonymous) @ debuggerWorker.js:72
ExceptionsManager.js:73 TypeError: TypeError: Cannot read property '0' of undefined

This error is located at:
    in ShowLunch (at navigationStore.js:319)
    in Wrapped (at SceneView.js:31)
    in SceneView (at CardStack.js:412)
    in RCTView (at View.js:113)
    in View (at CardStack.js:411)
    in RCTView (at View.js:113)
    in View (at CardStack.js:410)
    in RCTView (at View.js:113)
    in View (at createAnimatedComponent.js:134)
    in AnimatedComponent (at Card.js:26)
    in Card (at PointerEventsContainer.js:55)
    in Container (at CardStack.js:454)
    in RCTView (at View.js:113)
    in View (at CardStack.js:383)
    in RCTView (at View.js:113)
    in View (at CardStack.js:382)
    in CardStack (at CardStackTransitioner.js:97)
    in RCTView (at View.js:113)
    in View (at Transitioner.js:192)
    in Transitioner (at CardStackTransitioner.js:49)
    in CardStackTransitioner (at StackNavigator.js:60)
    in Unknown (at createNavigator.js:52)
    in Navigator (at createNavigationContainer.js:210)
    in NavigationContainer (at Router.js:70)
    in App (at Router.js:91)
    in Router (at LunchRouter.js:31)
    in LunchRouter (at App.js:16)
    in RCTView (at View.js:113)
    in View (at App.js:14)
    in App (created by AwakeInDevApp)
    in RCTView (at View.js:113)
    in View (created by AwakeInDevApp)
    in AwakeInDevApp (at registerRootComponent.js:34)
    in RootErrorBoundary (at registerRootComponent.js:33)
    in ExpoRootComponent (at renderApplication.js:35)
    in RCTView (at View.js:113)
    in View (at AppContainer.js:102)
    in RCTView (at View.js:113)
    in View (at AppContainer.js:122)
    in AppContainer (at renderApplication.js:34)
    at ShowLunch.lunchView (ShowLunch.js:54)
    at ShowLunch.proxiedMethod (createPrototypeProxy.js:44)
    at ShowLunch.render (ShowLunch.js:72)
    at ShowLunch.proxiedMethod (createPrototypeProxy.js:44)
    at finishClassComponent (ReactNativeFiber-dev.js:1667)
    at updateClassComponent (ReactNativeFiber-dev.js:1659)
    at beginWork (ReactNativeFiber-dev.js:1786)
    at performUnitOfWork (ReactNativeFiber-dev.js:2528)
    at workLoop (ReactNativeFiber-dev.js:2554)
    at Object._invokeGuardedCallback (ReactNativeFiber-dev.js:73)
reactConsoleErrorHandler @ ExceptionsManager.js:73
console.error @ YellowBox.js:71
componentDidCatch @ RootErrorBoundary.js:71
proxiedMethod @ createPrototypeProxy.js:44
commitErrorHandling @ ReactNativeFiber-dev.js:2675
commitAllLifeCycles @ ReactNativeFiber-dev.js:2462
_invokeGuardedCallback @ ReactNativeFiber-dev.js:73
invokeGuardedCallback @ ReactNativeFiber-dev.js:47
commitAllWork @ ReactNativeFiber-dev.js:2485
workLoop @ ReactNativeFiber-dev.js:2555
performWorkCatchBlock @ ReactNativeFiber-dev.js:2587
_invokeGuardedCallback @ ReactNativeFiber-dev.js:73
invokeGuardedCallback @ ReactNativeFiber-dev.js:47
performWork @ ReactNativeFiber-dev.js:2604
batchedUpdates @ ReactNativeFiber-dev.js:2756
batchedUpdates @ ReactNativeFiber-dev.js:202
batchedUpdatesWithControlledComponents @ ReactNativeFiber-dev.js:209
_receiveRootNodeIDEvent @ ReactNativeFiber-dev.js:3559
receiveTouches @ ReactNativeFiber-dev.js:3572
__callFunction @ MessageQueue.js:302
(anonymous) @ MessageQueue.js:116
__guard @ MessageQueue.js:265
callFunctionReturnFlushedQueue @ MessageQueue.js:115
(anonymous) @ debuggerWorker.js:72
ShowLunch.js:24 RESPONSE OK : GET LUNCH, ID: 5
ShowLunch.js:27 {id: 5, title: "Coconut, Beef and Winter melon ", description: "["Propre subline nom origines sans vers.", "Italiq…rent mille qui.", "Pour nostalgique fin chemin."]", portion: 4, supply: "Aucun", …}
ShowLunch.js:28 Headers {map: {…}}
ExceptionsManager.js:73 Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.

Please check the code for the ShowLunch component.

I tried several things with the bind (this) or the arrows functions but I don't understand.

1 Answer 1

2

This is a typical UI issue in React. All you have to do is create an if statement that will check if any the variables you need are not set. If that is the case, then you need to display a UI that shows a loading message or spinner.

render() {
  if (someVariableIsNotSet) {
    // e.g. if (!lunch) // but make sure to set `lunch: null` in initial state

    return <Text>Loading ...</Text>;
  }

  return (
    {/* Your main view for this component */}
  );
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you very much for your answer it's perfect.
Do you have a little explanation ?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.