null is not an object evaluating this.state.<name> - json

The problem might be common but I am asking because I couldn't fix it. I am getting "null is not an object(evaluating 'this.state.albums')" at line 22
And also I am a bit not clear about the type of data that was returned after the call and how to handle it. Please, can someone help me in explaining this? I am in the learning phase. when I am directly alert the response.data I'm getting [object][object] I have to do JSON stringify to see the data. Why should we do this?
import React, { Component } from 'react';
import {Text} from 'react-native';
import axios from 'axios';
export default class AlbumList extends Component{
constructor(props) {
super(props);
state = { albums : []};
}
componentWillMount(){
console.log('in componentWillMount');
//debugger;
//alert("first"+this.state);
axios.get('https://rallycoding.herokuapp.com/api/music_albums')
.then((response) => {
//console.log(response);
//alert(JSON.stringify(response));
this.setState({albums : response.data});
//alert(JSON.stringify(this.state.albums));
})
.catch((error) => {
alert(error);
});
}
renderAlbums(){
return this.state.albums.map( album => <Text>{album.title}</Text>); //line 22
}
componentDidMount() {
console.log('I was triggered during componentDidMount')
}
render(){
return(
<Text>{this.renderAlbums()}</Text>
//<Text>Hiii</Text>
);
}
}

You're missing this in your constructor.
constructor(props) {
super(props);
this.state = { albums : []};
}
As for the alert, you can't alert an object it has to be a string. So alerting a JSON object is just [object object]. If you use JSON.stringify it converts the object to a string that can be used for the alert. In your console you can log objects fine, and their structure is more readable. I would stick to console.log for debugging.

Related

react-native: Using async/await with setState

I have this simple code.
export default class ProductDetail extends Component {
constructor(props) {
super(props);
this.state = { test: null,id:this.props.navigation.state.params.productId };
console.log(1);
}
componentWillMount() {
console.log(2);
this.getProductRequest(this.state.id);
console.log(3);
}
async getProductRequest(id) {
try {
let api_token = await AsyncStorage.getItem('apiToken')
let response = await fetch('...')
let json = await response.json();
this.setState({test: json});
} catch(error) {
//
}
}
render() {
console.log(4);
console.log(this.state.test);
return (
<View><Text>test</Text></View>
);
}
}
Now, I checked it in a debuger:
I expect this result:
1
2
3
4
{data: {…}, status: "success", ...}
But I get this:
1
2
3
4
null
4
{data: {…}, status: "success", ...}
I think it means render() run twice!
how can I handle this error?
I think it means render() run twice!
It does: Once before your async result is available, and then again when it is and you use setState. This is normal and expected.
You can't hold up the first render waiting for an async operation to complete. Your choices are:
Have the component render appropriately when it doesn't have the data yet. Or,
If you don't want to render the component at all until the async operation has completed, move that operation in to the parent component and only render this component when the data is available, passing the data to this component as props.
Just to add to T.J Crowder's answer, one thing I like to do is return an ActivityIndicator if data is not received yet.
import {
View,
Text,
ActivityIndicator
} from 'react-native';
export default class ProductDetail extends Component {
... your code ...
render() {
if (!this.state.test) {
return <ActivityIndicator size='large' color='black' />
}
console.log(4);
console.log(this.state.test);
return (
<View><Text>test</Text></View>
);
}
}

How to save a list of json data that i get from an API to a class property using fetch

I'm trying to call a localhost API that i created in my react app class. This API will return a list of json data, i'm trying to save these results in a property
I don't know much about Reacjs. What i have tried so far is to create a method that will call the API and return the data, the i call this method in my class and save the results in a property.
The type of this method is Promise since the results that i'm expectibng are a list of data :
let items: any[];
function getIncidentsFromApiAsync(): Promise<any[]>{
return fetch('http://localhost:3978/calling')
.then((response) => response.json())
}
export class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
constructor(props: {}) {
super(props);
getIncidentsFromApiAsync().then(json => items = json);
}
}
I haven't been able to see the results since items is always undefined after calling getIncidentsFromApiAsync() method.
You can handle this in React using State and lifecycle method componentDidMount that gets called when the component is ready:
function getIncidentsFromApiAsync(): Promise<any[]>{
return fetch('http://localhost:3978/calling').then(
(response) => response.json()
);
}
export class App extends React.Component<{}, IDetailsListCustomColumnsExampleState> {
constructor(props: {}) {
super(props);
this.state = {
items: []
};
}
componentDidMount() {
getIncidentsFromApiAsync().then(json => this.setState({ items: json });
}
render() {
if (this.state.items.length) {
const itemsList = this.state.items.map((item) => <li key={item}>{item}</li>);
return (
<div>
<ul>{itemsList}</ul>
</div>
);
}
return <div>List is not available</div>;
}
}

load local jSON file in Reactjs without installing a localserver

I have a structure of src/resource/file.json.
1.By installing load-json and using require:
class App extends Component{
constructor(props) {
super(props);
this.state = {summaryData: [], sortBy: null};
this.sortContent = this.sortContent.bind(this);
}
componentWillMount() {
require('../resource/file.json')
.then(response => {
// Convert to JSON
return response;
})
.then(findresponse => {
// findresponse is an object
console.log(findresponse);
this.setState({summaryData: findresponse});
})
.catch(norespone => {
console.log('Im sorry but i could not fetch anything');
});
}
And appears the message :
Module not found: Can't resolve '../resource/file.json' in 'C:\Xampp\htdocs\path\to\app\src\pages'
Through myJSON:
request('https://api.myjson.com/bins/{id..}').then(sumres => {
if (sumres) {
this.setState({summaryData: sumres});
console.log(this.state.summaryData);
}
});
}
But nothing appears in the console or the network tab. Cans someone propose a solution?
Is it possible to load the json file without installing a local server?
Yes! It is possible to load JSON into your page. At the top of script where you import your modules, import your json file.
Example:
import React from 'react';
import jsonData from '../resource/file.json';
etc...
And in your case, if you're trying to set it to state, just set the state when the component initializes.
constructor(props) {
super(props);
this.state = {
summaryData: jsonData.myArray,
sortBy: null
};
this.sortContent = this.sortContent.bind(this);
}
Hope this helps!

How to fetch JSON API data and show that on Page using react.js

I want to fetch all data from "https://blockchain.info/api/exchange_rates_api" and show that on Page. I tried it but got an error message. Here is my Code :
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(){
super();
this.state = {
data: []
}
}
componentDidMount()
{
fetch("https://blockchain.info/ticker").
then((Response) => Response.json()).
then ((findresponse)=>
{
console.log(findresponse)
this.setState({
data:findresponse
});
})
}
render()
{
return(
<div>
{
this.state.data.map((dynamicData, Key) =>
<div>
<span>{dynamicData}</span>
</div>
)
}
</div>
)
}
}
export default App;
I got an error in setState method. When I m trying to write without setState method, I got data in the console. But I want data on the page in Table form.
You are getting an object from the API call but you need an array in order to use map, so you need to do this:
fetch("https://blockchain.info/ticker").
then((Response) => Response.json()).
then ((findresponse)=>
{
this.setState({
data: [findresponse] //wrap findresponse brackets to put the response in an array
});
})
Problem is that what you receive as JSON response from api call is an object not array. Objects don't have defined map function. First you need to convert object into an array.

React Native, Navigating a prop from one component to another

handleShowMatchFacts = id => {
// console.log('match', id)
return fetch(`http://api.football-api.com/2.0/matches/${id}?Authorization=565ec012251f932ea4000001fa542ae9d994470e73fdb314a8a56d76`)
.then(res => {
// console.log('match facts', matchFacts)
this.props.navigator.push({
title: 'Match',
component: MatchPage,
passProps: {matchInfo: res}
})
// console.log(res)
})
}
I have this function above, that i want to send matchInfo to matchPage.
I take in that prop as follows below.
'use strict'
import React from 'react'
import { StyleSheet, View, Component, Text, TabBarIOS } from 'react-native'
import Welcome from './welcome.js'
import More from './more.js'
export default class MatchPage extends React.Component {
constructor(props) {
super(props);
}
componentWillMount(){
console.log('mathc facts ' + this.props.matchInfo._bodyInit)
}
render(){
return (
<View>
</View>
)
}
}
All the info I need is in that object - 'this.props.matchInfo._bodyInit'. My problem is that after '._bodyInt', I'm not sure what to put after that. I've tried .id, .venue, and .events, they all console logged as undefined...
You never change props directly in React. You must always change the state via setState and pass state to components as props. This allows React to manage state for you rather than calling things manually.
In the result of your api call, set the component state:
this.setState({
title: 'Match',
component: MatchPage,
matchInfo: res
}
Then pass the state as needed into child components.
render() {
return(
<FooComponent title={this.state.title} matchInfo={this.state.matchInfo} />
);
}
These can then be referenced in the child component as props:
class FooComponent extends Component {
constructor(props) {
super(props);
}
componentWillMount() {
console.log(this.props.title);
console.log(this.props.matchInfo);
// Etc.
}
}
If you need to reference these values inside the component itself, reference state rather than props.
this.state.title;
this.state.matchInfo;
Remember components manage their own state and pass that state as props to children as needed.
assuming you are receiving json object as response , you would need to parse the response before fetching the values.
var resp = JSON.parse(matchInfo);
body = resp['_bodyInit'];