0

I am working on implementing an RSS feed into my application. There seems to be a problem passing my State Variable object array 'NDA_news' to the render function.

I have console logs showing that the given state array is a deepcopy (thank you lodash), but it is not an object in scope of render.

Any ideas, suggestions, etc. would be greatly appreciated! I am a new react-native developer so I may be missing something obvious.

alumniScreen.js

import React, {Component} from 'react';
import { Text,
    View,
    SafeAreaView,
    ScrollView,
    Image,
    TouchableOpacity,
    StyleSheet,
    Dimensions,
} from 'react-native';
import Modal from 'react-native-modal';
import {COLORS} from './colors.js';     //Color Sheet
import SideMenu from './sideMenu.js';
import Card from './shared/Card.js';
import * as rssParser from 'react-native-rss-parser';
import _ from "lodash";

const WIDTH = Dimensions.get("window").width;
const HEIGHT = Dimensions.get("window").height;


export default class alumni extends React.Component {
    constructor(props: Props) {
        super(props);
        this.state={
            NDA_news: []
        }
    }
    
    componentDidMount(){
        this.fetchData();
  }
    
    fetchData(){
        console.log("...inFetch");
        
        fetch('https://www.notredameacademy.com/rss.cfm?news=0')
        .then(response => response.text())
        .then(responseData => rssParser.parse(responseData))
        .then((rss) => {
            this.state.NDA_news = _.cloneDeep(rss.items);
            if(console.log(this.state.NDA_news === rss.items))
            {
                console.log("this is a shallow copy");
            }
            else
                console.log("this is a deep copy");
            
            console.log(this.state.NDA_news[0].title);
            this.state.NDA_news.bind(this);
            }); 
        
    }
    render() {
        console.log("inRender");
        
        return (
            <SafeAreaView>
                <Text>{this.state.NDA_news[0].title}</Text>
            </SafeAreaView>
        );
    }
}

Console Output:

info Reloading app...
[Wed Dec 23 2020 14:49:16.194]  BUNDLE  ./index.js

[Wed Dec 23 2020 14:49:17.130]  LOG      Running "NDA" with {"rootTag":1}
[Wed Dec 23 2020 14:49:18.938]  LOG      inRender
[Wed Dec 23 2020 14:49:18.971]  LOG      ...inFetch
[Wed Dec 23 2020 14:49:19.369]  LOG      false
[Wed Dec 23 2020 14:49:19.370]  LOG      Sounds of the Season
[Wed Dec 23 2020 14:50:34.254]  LOG      inRender
[Wed Dec 23 2020 14:50:34.258]  LOG      ...inFetch
[Wed Dec 23 2020 14:50:34.440]  LOG      false
[Wed Dec 23 2020 14:50:34.441]  LOG      this is a deep copy
[Wed Dec 23 2020 14:50:34.442]  LOG      Sounds of the Season
[Wed Dec 23 2020 14:51:48.000]  LOG      inRender
[Wed Dec 23 2020 14:51:48.130]  LOG      inRender
[Wed Dec 23 2020 14:51:48.370]  ERROR    TypeError: undefined is not an object (evaluating 'this.state.NDA_news[0].title')

This error is located at:
    in alumni
    in StaticContainer
    in StaticContainer (at SceneView.tsx:115)
    in EnsureSingleNavigator (at SceneView.tsx:114)
    in SceneView (at useDescriptors.tsx:153)
    in RCTView (at View.js:34)
    in View (at CardContainer.tsx:245)
    in RCTView (at View.js:34)
    in View (at CardContainer.tsx:244)
    in RCTView (at View.js:34)
    in View (at CardSheet.tsx:33)
    in ForwardRef(CardSheet) (at Card.tsx:573)
    in RCTView (at View.js:34)
    in View (at createAnimatedComponent.js:165)
    in AnimatedComponent (at createAnimatedComponent.js:215)
    in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:555)
    in PanGestureHandler (at GestureHandlerNative.tsx:13)
    in PanGestureHandler (at Card.tsx:549)
    in RCTView (at View.js:34)
    in View (at createAnimatedComponent.js:165)
    in AnimatedComponent (at createAnimatedComponent.js:215)
    in ForwardRef(AnimatedComponentWrapper) (at Card.tsx:544)
    in RCTView (at View.js:34)
    in View (at Card.tsx:538)
    in Card (at CardContainer.tsx:206)
    in CardContainer (at CardStack.tsx:619)
    in RCTView (at View.js:34)
    in View (at Screens.tsx:84)
    in MaybeScreen (at CardStack.tsx:612)
    in RCTView (at View.js:34)
    in View (at Screens.tsx:54)
    in MaybeScreenContainer (at CardStack.tsx:494)
    in CardStack (at StackView.tsx:462)
    in KeyboardManager (at StackView.tsx:458)
    in RNCSafeAreaProvider (at SafeAreaContext.tsx:74)
    in SafeAreaProvider (at SafeAreaProviderCompat.tsx:42)
    in SafeAreaProviderCompat (at StackView.tsx:455)
    in GestureHandlerRootView (at GestureHandlerRootView.android.js:31)
    in GestureHandlerRootView (at StackView.tsx:454)
    in StackView (at createStackNavigator.tsx:87)
    in StackNavigator (at App.js:24)
    in EnsureSingleNavigator (at BaseNavigationContainer.tsx:409)
    in ForwardRef(BaseNavigationContainer) (at NavigationContainer.tsx:91)
    in ThemeProvider (at NavigationContainer.tsx:90)
    in ForwardRef(NavigationContainer) (at App.js:23)
    in App (at renderApplication.js:45)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:106)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:132)
    in AppContainer (at renderApplication.js:39)
1
  • 1
    you are accessing your content before setting it, make loader set and set it after API finish Commented Dec 23, 2020 at 21:06

1 Answer 1

1

Do it like this

Problems

  1. dont mutate state without setState
  2. you can not get updated state after setting it unless you are not using callback of setState
  3. you are calling API and its async operation that's why you need to wait for some time to load that function and that's why you need one loading flag to check async function calling finished or not
import React, { Component } from 'react';
import {
  Text,
  View,
  SafeAreaView,
  ScrollView,
  Image,
  TouchableOpacity,
  StyleSheet,
  Dimensions,
} from 'react-native';
import Modal from 'react-native-modal';
import { COLORS } from './colors.js'; //Color Sheet
import SideMenu from './sideMenu.js';
import Card from './shared/Card.js';
import * as rssParser from 'react-native-rss-parser';
import _ from 'lodash';

const WIDTH = Dimensions.get('window').width;
const HEIGHT = Dimensions.get('window').height;

export default class alumni extends React.Component {
  constructor(props: Props) {
    super(props);
    this.state = {
      NDA_news: [],
      loading: true,
    };
  }

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    console.log('...inFetch');

    fetch('https://www.notredameacademy.com/rss.cfm?news=0')
      .then(response => response.text())
      .then(responseData => rssParser.parse(responseData))
      .then(rss => {
        // this.state.NDA_news = _.cloneDeep(rss.items);

        this.setState({ NDA_news: _.cloneDeep(rss.items), loading: false }, () => {
          if (console.log(this.state.NDA_news === rss.items)) {
            console.log('this is a shallow copy');
          } else {
            console.log('this is a deep copy');
          }
          console.log(this.state.NDA_news[0].title);
        });
      });
  }

  render() {
    console.log('inRender');

    if (this.state.loading) return <Text>Loading.....</Text>;

    return (
      <SafeAreaView>
        <Text>{this.state.NDA_news[0].title}</Text>
      </SafeAreaView>
    );
  }
}
Sign up to request clarification or add additional context in comments.

3 Comments

An explanation about why this works would improve this answer.
Yes I added an explanation
This works wonderfully! Thank you so much, I especially appreciate the explanation. I'm quite new still to react-native and javascript.

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.