React: Couldn't access properties within data after axios loads. Could it have something to do with params? - json

I'm coding MERN app and I'm almost done with it. However, I am having problems displaying a single customer page with data.
My App.js
import React from 'react';
import { BrowserRouter as Router, Route } from "react-router-dom";
import CustomersList from "./components/customers-list";
import customerRewards from './components/customerRewards';
import "bootstrap/dist/css/bootstrap.min.css";
function App() {
return (
<Router>
<div className="container">
<div className="header">
<h1>Wow Rewards Program</h1>
</div>
<Route path="/" exact component={CustomersList} />
<Route path='/:id' component={customerRewards} />
</div>
</Router>
);
}
export default App;
My Customer list Component to list customers in main page
import React, { Component } from 'react';
import axios from 'axios';
import CustomerCard from "./customerCard";
class CustomersList extends Component {
constructor(props) {
super(props);
this.state = {
customers: []
}
}
componentDidMount() {
axios.get('http://localhost:5000/customers/')
.then(response => {
this.setState({ customers: response.data });
})
.catch((error) => {
console.log(error);
})
}
render() {
const customers = this.state.customers;
console.log("customerList", customers);
let customersList;
if(!customers) {
customersList = "there is no customer record!";
} else {
customersList = customers.map((customer, k) =>
<CustomerCard customer={customer} key={k} />
);
}
return (
<div>
<h2>Customers List</h2>
<div>
<table>
<thead>
<tr>
<th>Account</th>
<th>Name</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{customersList}
</tbody>
</table>
</div>
</div>
)
}
}
export default CustomersList;
My CustomerCard Component to display each customer
import React from 'react';
import { Link } from 'react-router-dom';
const CustomerCard = (props) => {
const customerCard = props.customer;
return (
<tr>
<td>{customerCard.account}</td>
<td>{customerCard.name}</td>
<td>
<Link to={`/${customerCard.account}`}>view</Link>
</td>
</tr>
)
}
export default CustomerCard;
My Customer Rewards Component to list customer details
import React, { Component } from 'react';
import { Link} from 'react-router-dom';
import '../App.css';
import axios from 'axios';
class customerRewards extends Component {
constructor(props) {
super(props);
this.state = {
customerRewards: {}
};
}
componentDidMount() {
// const { accountId } = this.props.match.params;
console.log("Print id: " + this.props.match.params.id);
axios
.get('http://localhost:5000/customers/'+this.props.match.params.id)
.then(res => {
// console.log("Print-customerRewards-API-response: " + res.data);
this.setState({
customerRewards: res.data
})
})
.catch(err => {
console.log("Error from customerRewards");
})
};
render() {
const customerRewards = this.state.customerRewards;
console.log("customerID", customerRewards);
let CustomerItem = <div>
{customerRewards.purchase_history}
</div>
return (
<div >
<div className="container">
<div className="row">
<div className="col-md-10 m-auto">
<br /> <br />
<Link to="/" className="btn btn-outline-warning float-left">
Back
</Link>
</div>
<br />
<div className="col-md-8 m-auto">
<h1 className="display-4 text-center">Hello {customerRewards.name}</h1>
<p className="lead text-center">
{customerRewards.account}
</p>
<hr /> <br />
</div>
</div>
<div>
{ CustomerItem }
</div>
</div>
</div>
);
}
}
export default customerRewards;
this is my .json sample that I uploaded to MongoDB Atlas:
[
{
"account": "BCE456",
"name": "JohnDoe",
"purchase_history": [
{
"month": "Month01",
"transitions": [
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
}
]
},
{
"month": "Month02",
"transitions": [
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
}
]
}
]
},
{
"account": "ABC123",
"name": "JohnDoe",
"purchase_history": [
{
"month": "Month01",
"transitions": [
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
}
]
},
{
"month": "Month02",
"transitions": [
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
},
{
"date": "01/01/2010",
"purchase": 120
}
]
}
]
}
]
I can see that I was able to download the customer details in console.log("customerID", customerRewards); However, when I tried to access {customerRewards.name}, it won't display the name at all....
What am I missing? Could it have something to do with the params that I'm trying to link to? I tried to link by account instead of _id

Your piece of state, customerRewards is an array when it comes from the API. So even when you declare your initial state with an object {}, customerRewards is always going to be an array with one element in this case. Could be an issue in your API response - I'm not familiar with MongoDB Atlas or if it creates access patterns for you but you should be able to configure to return a singular object with a unique ID rather than an array of 1 element.
For now you could do:
this.setState({
customerRewards: res.data[0] /** could do res.data.shift() as well */
})
I would figure out why you are returning an array if there is only supposed to be one element coming back.

just select the element which name you want to get:
customerRewards[0].name

Related

convert json data to react components with ajax requests

I have a problem in convertion json data to react components with ajax requests.
My json file is under "src/data/form-inputs.json".
The content of form-inputs.json is
{
"form_inputs": [
{
"label": "Sender Email",
"name": "sender_mail",
"type": "email",
"value": null,
"rules": "required|min:3|max:64",
"options": [],
"default_value": null,
"multiple": false,
"readonly": false,
"placeholder": "Sender Email",
"info": "Example value of how to fill the input"
}
]
}
Under "src/components/form.js" is form.js file that converts json data to React.js components. The code of form.js is
import React, { Component } from 'react';
class Form extends Component {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
form_inputs: []
};
}
componentDidMount() {
fetch('../test-json/form-inputs.json')
.then(res => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
form_inputs: result.form_inputs
});
});
}
render() {
const {isLoaded, form_inputs} = this.state;
if(!isLoaded) {
return <div>Loading...</div>
}else{
return (
<div>
<ul>
{form_inputs.map(form_input => (
<li>
{form_input.label}
</li>
))}
</ul>
</div>
)
}
}
}
export default Form
Please can somebody help me with this problem?
Thank you very much in advance!
Import your json file. No need it parse it, javascript interpreter will automatically parse it for you. You don't need a state anymore in your component. Just loop in the imported json.
import React from "react";
import ReactDOM from "react-dom";
import formData from "./formData.json";
function App() {
return (
<div className="App">
<ul>
{formData.form_inputs.map(form_input => (
<React.Fragment>
<label for={form_input.label}>{form_input.label}</label>
<input
key={form_input.label}
id={form_input.label}
type={form_input.type}
name={form_input.name}
defaultValue={form_input.default_value}
placeholder={form_input.placeholder}
/>
</React.Fragment>
))}
</ul>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Here is a codesandbox link to see it in action.

How do I grab this API data using ReactJS

Hi Could anyone help with this? I am trying to grab my API data from this API request but cannot seem to manage how to grab the bit I need.
Basically what I need to display in my <p></p> is this "astronomical": "0.4838725338",
Here is my json data
{
"links": {
"next": "https=DEMO_KEY",
},
"element_count": 6,
"near_objects": {
"2018-12-28": [
{
"links": {
"self": "x"
},
"id": "2450238",
"estimated_diameter": {
"kilometers": {
"estimated": 0.6089126221,
"estimatedmax": 1.3615700154
}
},
"is_potentially": false,
"approach": [
{
"date": "2018-12-28",
"epoch": 1545984000000,
"distance": {
"astronomical": "0.4838725338",
"lunar": "188.2264099121",
},
"orbitinody": "Nobes"
}
],
And here is my Component
class App extends Component {
state = {
data : []
}
componentDidMount() {
this.fetchasa();
}
fetchasa = () => {
fetch('https:?de_KEY')
.then((response) => response.json())
.then((result) => this.setState({
data: result.near_objects.2018-12-28.approach.distance[0]
}))
}
render() {
const {data} = this.state;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>Edit <code>src/App.js</code> and save to reload.</p>
<p>astronomical: {data}</p>
</header>
</div>
);
}
}
export default App;
Please help and thank you in advance :D
Try with:
result.near_objects['2018-12-28'][0].approach[0].distance.astronomical
If you don't know the index names of near_objects prior to the request, you can get the date value like this
const [first] = Object.keys(result.near_objects)
result.near_objects[first][0].approach[0].distance.astronomical

My React navigation is dynamic, warning : You should only render one navigator explicitly in your app

I'm struggling to make my dynamic navigation working in my react-native app.
Here is what I have on my AppNavigation.js :
import {
createDrawerNavigator,
createStackNavigator,
createSwitchNavigator, DrawerItems, SafeAreaView
} from 'react-navigation'
import LoginScreen from '../screens/LoginScreen'
import ProfileScreen from "../screens/ProfileScreen";
import TemplatesScreen from "../screens/TemplatesScreen";
import AuthLoadingScreen from "../screens/AuthLoadingScreen";
import React from "react";
import {Button, Icon} from "native-base";
import {ScrollView} from "react-native";
import NewFilmScreen from "../screens/NewFilmScreen";
import SettingsScreen from "../screens/SettingsScreen";
import LogoutScreen from "../screens/LogoutScreen";
import TemplateWorkflowContainer from "./TemplateWorkflowContainer";
const WorkflowContainer = createStackNavigator(
{
TemplateContainer: {
screen: TemplateWorkflowContainer
}
},
{
headerMode: 'none',
}
);
// drawer stack
const AppNavigation = createDrawerNavigator({
TemplatesScreen: {screen: TemplatesScreen},
NewFilm: {screen: NewFilmScreen},
ProfileScreen: {screen: ProfileScreen},
SettingsScreen: {screen: SettingsScreen},
LogoutScreen: {screen: LogoutScreen}
},
{
drawerBackgroundColor: '#ff4559',
// Default config for all screens
headerMode: 'none',
initialRouteName: 'TemplatesScreen',
contentOptions: {
activeTintColor: '#fff',
inactiveTintColor: '#fff',
itemsContainerStyle: {
marginVertical: 0,
},
itemStyle: {
flexDirection: 'row-reverse',
},
iconContainerStyle: {
opacity: 0.8,
}
},
contentComponent: props =>
<ScrollView>
<SafeAreaView forceInset={{top: 'always', horizontal: 'never'}}>
<Button transparent>
<Icon name='close' style={{fontSize: 40, color: 'white'}} onPress={() => {
props.navigation.closeDrawer()
}}/>
</Button>
<DrawerItems {...props} />
</SafeAreaView>
</ScrollView>
});
const WrapperStack = createStackNavigator({
AppDrawer: AppNavigation,
WorkflowContainer: WorkflowContainer
},
{
headerMode: 'none'
}
);
// Manifest of possible screens, when the user sign in the loginStack will be unmount to never logged out the user with
// the back button
const PrimaryNav = createSwitchNavigator({
AuthLoading: {screen: AuthLoadingScreen},
Auth: {screen: LoginScreen},
App: {screen: WrapperStack}
}, {
initialRouteName: 'AuthLoading'
});
export default PrimaryNav;
My drawer is fine. The problem is on the WorkflowContainer. This is a navigation like this :
import React, { Component } from "react";
import { createStackNavigator } from "react-navigation";
import TemplateWorkflowNavigator from "./TemplateWorkflowNavigator";
export default class TemplateWorkflowContainer extends Component {
constructor(props) {
super(props);
this.state = {
content: null
};
}
generateScreens = data => {
const stack = {};
stack["0"] = {
screen: TemplateWorkflowNavigator,
navigationOptions: () => ({
title: data.title,
gesturesEnabled: true
})
};
for (let i = 0; i < data.scenes.length; i++) {
let screenNumber = data.scenes[i].priority + 1;
stack[screenNumber] = {
screen: TemplateWorkflowNavigator,
navigationOptions: () => ({
title: data.scenes[i].name,
gesturesEnabled: true
})
};
}
return stack;
};
renderStackNavigo = aTemplate => {
const TemplateStackNavigor = createStackNavigator(
this.generateScreens(aTemplate), {headerMode: 'none'}
);
return <TemplateStackNavigor screenProps={aTemplate}/>;
};
render() {
return this.props.navigation.state.params.json && this.renderStackNavigo(this.props.navigation.state.params.json);
}
}
It's dynamic, throught the this.props.navigation.state.params.jsoni got back a JSON like this :
{
"id": 5,
"title": "toto",
"dolly": 74,
"name": "toto",
"conditions": [
{
"name": "Calm",
"desc": "test",
"priority": 0
}
],
"medias": [
{
"path": "a_path_here",
"mobile_path": "a_path_here",
"size": 80851,
"type": "preview"
}
],
"scenes": [
{
"name": "Intro",
"priority": 0,
"conditions": [
{
"name": "smile",
"desc": "test",
"priority": 0
}
],
"medias": [
{
"path": "a_path_here",
"mobile_path": "a_path_here",
"size": 80851,
"type": "preview"
}
],
"elements": [
{
"name": "Name",
"priority": 0,
"type": "text",
}
]
}
]
}
It's working when I call this
this.props.navigation.navigate("TemplateContainer", { json: path });
But I have this warning :
You should only render one navigator explicitly in your app, and other
navigators should by rendered by including them in that navigator.
I tried a lot of things, but I'm so new on react native, nothing worked.
How can I make this navigation works with no warning ? What changes do I have to apply ?
As my assumption, your TemplateWorkflowContainer will look like this
export default class TemplateWorkflowContainer extends Component {
static router = null;
...
renderStackNavigo = aTemplate => {
const TemplateStackNavigor = createStackNavigator(
this.generateScreens(aTemplate), {headerMode: 'none'}
);
TemplateWorkflowContainer.router = TemplateStackNavigor.router;
return <TemplateStackNavigor screenProps={aTemplate}/>;
};
...
}

Import JSON data in to array in REACTJS

So ive been looking at this for a couple hours now trying to get my head around it but I just cant figure it out.
I have a json file located at '/src/data/topbar.json' which i want to include in my topbar-container component which will be used to generate the top menu.
What am I doing wrong here?
topbar.json:
{
"topbarLinks": [
{
"id": 1,
"icon": "header__topbar__list__link__icon glyphicon glyphicon-home",
"text": "home",
"link": "/"
},
{
"id": 2,
"icon": "header__topbar__list__link__icon glyphicon glyphicon-euro",
"text": "Pricing",
"link": "/pricing"
},
{
"id": 3,
"icon": "header__topbar__list__link__icon glyphicon glyphicon-exclamation-sign",
"text": "Help",
"link": "/help"
},
{
"id": 4,
"icon": "header__topbar__list__link__icon glyphicon glyphicon-question-sign",
"text": "FAQ",
"link": "/faq"
},
{
"id": 5,
"icon": "header__topbar__list__link__icon glyphicon glyphicon-edit",
"text": "Register",
"link": "/register"
},
{
"id": 6,
"icon": "header__topbar__list__link__icon glyphicon glyphicon-share",
"text": "Login",
"link": "/login"
}
]
}
topbar-container.js
import React, { Component } from 'react';
import './topbar-container.scss';
import Link from '../topbar-link/topbar-link';
require ('../../data/topbar.json');
class TopbarContainer extends Component {
constructor() {
super();
this.State = {
topbarLinks: []
}
}
componentDidMount() {
fetch('../../data/topbar.json')
.then(results => {
return results.json();
}).then(data => {
let topbarLinks = data.results.map((topbarLinks, key) => {
return (
<Link
key={topbarLinks.id}
text={topbarLinks.text}
icon={topbarLinks.icon}
link={topbarLinks.link}
/>
)
})
})
}
render() {
return (
<div className="container-fluid header__topbar">
<div className="row">
<div className="container">
<ul className="header__topbar__list">
{this.state.topbarLinks}
</ul>
</div>
</div>
</div>
);
}
}
export default TopbarContainer;
You can't fetch a local JSON file, you either have to import it, or setup a webserver that will serve that JSON file
import myJson from '../../data/topbar.json';
Then just map over it and don't forget to setState
componentDidMount() {
let topbarLinks = myJson.topbarLinks.map((topbarLinks, key) => {
return (
<Link
key={topbarLinks.id}
text={topbarLinks.text}
icon={topbarLinks.icon}
link={topbarLinks.link}
/>
)
})
this.setState({topbarLinks: topbarLinks}); // <--
//or just this.setState({ topbarLinks });
}
and as somebody else noted this.state has to be lowercase
topbar.json:
export default {
"topbarLinks": []
}
then you can simply import it without fetch
import data from '../../data/topbar.json'
let topbarLinks = data.results.map((topbarLinks, key) => {
return (
;
I don't think that State should be capitalized in this.State in your constructor.
Change map function to data.topbarLinks.map to access json data.
let topbarLinks = data.topbarLinks.map((topbarLinks, key) => {
return (
<Link
key={topbarLinks.id}
text={topbarLinks.text}
icon={topbarLinks.icon}
link={topbarLinks.link}
/>
)
})
And then set state
this.setState({topbarLinks: topbarLinks});
Change your initial state as this.State to this.state in constructor.

how do i access individual data in json data

I am receiving the json data from server as like this
[{
"_id": "588b3731d4428e2ff05ddefa",
"Id": 50,
"Name": "Vishruth",
"Age": 11
}, {
"_id": "588b45df255e323de55ac333",
"Id": 51,
"Name": "Vishruth",
"Age": 11
}]
how do i access the individual data from it
import React from 'react';
import axios from 'axios';
//require('./style.scss');
class Premontessori extends React.Component{
constructor(props){
super(props);
this.state={
post:[]
};
}
componentDidMount(){
let self = this;
axios.get('http://localhost:8080/list')
.then(function(data) {
console.log(data);
self.setState({post:data});
});
}
render(){
return(
<div>
{JSON.stringify(this.state.post.data)}
</div>
);
}
}
export default Premontessori;
Your data is an array. You can simple use map to loop over all elements of the array and then access individual elements of the javascript object using the dot notation or the bracket notation.
class Premontessori extends React.Component{
constructor(props){
super(props);
this.state={
post:[]
};
}
componentDidMount(){
var data = [{
"_id": "588b3731d4428e2ff05ddefa",
"Id": 50,
"Name": "Vishruth",
"Age": 11
}, {
"_id": "588b45df255e323de55ac333",
"Id": 51,
"Name": "Vishruth",
"Age": 11
}]
this.setState({post:data});
}
render(){
return(
<div>
<tbody>
{this.state.post.map(function(item, index) {
return (
<tr>
<td>{item._id}</td>
<td>{item.Id}</td>
<td>{item.Name}</td>
<td>{item.Age}</td>
</tr>
)
})
}</tbody>
</div>
)
}
}
ReactDOM.render(<Premontessori/>, document.getElementById("app"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"><div>