Unhandled Rejection (TypeError): Cannot read property 'filter' of undefined - json

I am trying to filter search my API data in react.js but I'm getting this error, cannot read property 'filter' of undefined. This is my JSON data link: https://alert-amigo-api.herokuapp.com/products/
Since the JSON data returns an array of objects, I have declared that in the props and used the same. What is the problem?
import FilterResults from 'react-filter-search';
import React, { Component } from "react";
class UserProfile extends Component {
constructor(props) {
super(props);
this.state = {
error: null,
isLoaded: false,
products: [],
value: ''
};
}
componentWillMount() {
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => response.json())
.then(
(result) => {
this.setState({
isLoaded: true,
products: result.products
});
},
// Note: it's important to handle errors here
// instead of a catch() block so that we don't swallow
// exceptions from actual bugs in components.
(error) => {
this.setState({
isLoaded: true,
error
});
}
)
console.log(this.state.products[0]);
}
handleChange = event => {
const { value } = event.target;
this.setState({ value });
};
render() {
const { error, isLoaded, products, value } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div className="content-margin">
<input type="text" value={value} onChange={this.handleChange} />
<FilterResults
value={value}
products={products}
renderResults={products => (
<div>
{products.map(el => (
<div>
<span>{el.productName}</span>
</div>
))}
</div>
)}
/>
</div>
);
}
}
}
export default UserProfile;

By testing that exact example, you will notice that the fetch URL does not return products:
fetch('https://jsonplaceholder.typicode.com/users')
The URL should be:
fetch('https://alert-amigo-api.herokuapp.com/products/')
Now result.products does contain an array. I suggest slightly bullet-proofing your code:
(result) => {
this.setState({
isLoaded: true,
products: result.products || [] // <-- add empty array
});
Or, if you prefer, on the render method:
render() {
{ products &&
<FilterResults ... />
}
}

Related

Trouble display name property from axios fetched json object

https://codesandbox.io/s/currying-voice-toq9t - I am trying to save the json object into the component state, then render the name into the browser.
getProfile() {
axios
.get(
"https://cors-anywhere.herokuapp.com/" +
"https://phantombuster.s3.amazonaws.com....."
)
.then(response => {
this.setState({
profile: {
name: response.data.name
}
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
Your Response data is an array form so,You need to give Index.I hope it will helps you.
getProfile() {
axios
.get(
"https://cors-anywhere.herokuapp.com/" +
"https://phantombuster.s3.amazonaws.com/YRrbtT9qhg0/NISgcRm5hpqtvPF8I0tLkQ/result.json"
)
.then(response => {
this.setState({
profile: {
name: response.data[0].name
}
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
The response.data is an array where in first position there is the information that you are looking for, so the setState should be like this:
this.setState({
profile: {
name: response.data[0].name
}
});
or
const [obj] = response.data;
this.setState({
profile: {
name: obj.name
}
});
Your response.data returns an array.so you need to traverse it inside a loop.
import React from "react";
import ReactDOM from "react-dom";
import axios from "axios";
export class Profile extends React.Component {
constructor(props) {
super(props);
this.state = { profile: [] };
}
componentDidMount() {
this.getProfile();
}
getProfile() {
axios
.get(
"https://cors-anywhere.herokuapp.com/" +
"https://phantombuster.s3.amazonaws.com/YRrbtT9qhg0/NISgcRm5hpqtvPF8I0tLkQ/result.json"
)
.then(response => {
console.log("response: ", response)
this.setState({
profile: response.data
});
})
.catch(error => this.setState({ error, isLoading: false }));
}
render() {
let { name } = this.state.profile;
const { error } = this.state;
return (
<div className="App">
<header className="App-header">
<h1 className="App-title">Profile</h1>
{error ? <p>{error.message}</p> : null}
</header>
<div className="App-feeds" />
<div className="panel-list">
{this.state.profile.map((element) => <p>First Name: {element.name}</p>)}
</div>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Profile />, rootElement);

How do I make my table dynamically change based on year?

I'm trying to populate a table with some information pulled from my database through an API based on year. I'm using React Router and would like to keep my sidebar with the links to different years, but dynamically change the table that is the main focus of this page.
I can get the Table to render with the first year(2019, since this is the default link), but that's only if it's outside the <Switch>. This also causes the problem that it doesn't change when the link changes.
class YearlyTable extends React.Component {
state = {
yearlyTable: [],
isLoading: false,
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(
`http://localhost/yearTable/${this.props.match.params.yearId}${this.props.location.search}`,
{ withCredentials: true }
).then(res => {
const yearlyTable = res.data;
this.setState({ yearlyTable, isLoading: false });
}).catch((error) => {
console.log(error);
});
}
render() {
// isLoading component
// Check what API returns
console.log(this.state.yearlyBonds);
return (
// Removed for simplicity
// This returns a table
{this.state.yearlyTable && <ListTable title={this.state.yearlyTable.Title} data={this.state.yearlyTable.Bonds} />}
// This does not
<Switch>
<Route exact path={`/yearly_table/${this.props.match.params.yearId}${this.props.location.search}`} render={() => this.state.yearlyTable && <ListTable title={this.state.yearlyTable.Title} data={this.state.yearlyTable} />} />
</Switch>
// Sidebar removed for simplicity
);
}
}
export default withRouter(YearlyTable);
The outcome I'm wanting to achieve is that it renders the first table, but when you press one of the links, then it changes out the table with the new contents.
This is happening because you are using componentDidMount. This is called only for the first render, not after that.
You can do something like
class YearlyTable extends React.Component {
state = {
yearlyTable: [],
isLoading: false,
}
componentDidMount() {
this.setState({ isLoading: true });
axios.get(
`http://localhost/yearTable/${this.props.match.params.yearId}${this.props.location.search}`,
{ withCredentials: true }
).then(res => {
const yearlyTable = res.data;
this.setState({ yearlyTable, isLoading: false });
}).catch((error) => {
console.log(error);
});
}
updateData(){
axios.get(
`http://localhost/yearTable/newYearID${this.props.location.search}`,
{ withCredentials: true }
).then(res => {
const yearlyTable = res.data;
this.setState({ yearlyTable, isLoading: false });
}).catch((error) => {
console.log(error);
});
}
render() {
// isLoading component
// Check what API returns
console.log(this.state.yearlyBonds);
return (
// Removed for simplicity
// This returns a table
{this.state.yearlyTable && <ListTable title={this.state.yearlyTable.Title} data={this.state.yearlyTable.Bonds} />}
<Link onClick={this.updateData.bind(this, clickedItemYear)}>Some Item</Link>
);
}
}
export default withRouter(YearlyTable);
You can use and preventDefault or stopPropogation of the event. Better make a function call , so that it is called again whenever there is some user action.

Parsing JSON with react native, looping through

i am trying to parse a json file by displaying all the names in the clubs
the json file is https://raw.githubusercontent.com/openfootball/football.json/master/2017-18/it.1.clubs.json
my current code i have is
constructor(props) {
super(props);
this.state = {
isLoading: true,
dataSource: null,
}
}
componentDidMount() {
return fetch('https://raw.githubusercontent.com/openfootball/football.json/master/2017-18/it.1.clubs.json')
.then ( (response) => response.json() )
.then ( (responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson.clubs,
})
})
.catch((error) => {
console.log(error)
});
}
render() {
if (this.state.isLoading) {
return (
<View style = {styles.containter}>
<ActivityIndicator/>
</View>
)
} else {
return (
<View>
<Text>{this.state.dataSource.name}</Text>
</View>
)
I just want to loop through to display all the names in the clubs
Try this:
Couple of edits: Changing the initial state of dataSouce value as an array, this is to ensure it doesn't throw can't read property map of undefined.
You don't need to return the fetch call, because you don't need a promise to returned.
EDIT: Added a loading text before all the clubs are loaded.
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class App extends React.Component {
state = {
isLoading: false,
dataSource: []
};
componentDidMount() {
this.setState({ isLoading: true }, () => {
fetch(
"https://raw.githubusercontent.com/openfootball/football.json/master/2017-18/it.1.clubs.json"
)
.then(response => response.json())
.then(responseJson => {
console.log(responseJson);
this.setState({
isLoading: false,
dataSource: responseJson.clubs
});
})
.catch(error => {
this.setState({ loading: false });
console.log(error);
});
});
}
render() {
return (
<div className="App">
<h1>Club Names</h1>
{this.state.isLoading ? (
<h1>Loading Clubs...</h1>
) : (
this.state.dataSource.map(data => <h2 key={data.key}>{data.name}</h2>)
)}
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Sandbox Link: https://codesandbox.io/s/throbbing-dream-7lpcm?fontsize=14

Cannot access value of a json object ? Cannot read property 'company_about' of undefined ?

This is my JSON
[
{
"id": 1,
"job_id": 1,
"company_profile": "Sales and Marketing",
"company_about": "Established in 1992 , it is a renouned marketing company",
"company_product": "Ford,Mustang,Beetle",
"key_skills": "commmunication,english,spanish,german",
"qualification": "High School,Masters",
"job_description": "Must be a Local of Mumbai",
"created_at": null,
"updated_at": null
}
]
I am trying to get its values.
this is my react code to log them.
public getJobDetails = (jobid: number) => {
const JobId = jobid;
fetch('http://127.0.0.1:8000/api/jobs/detail/' + JobId)
.then(response => response.json())
.then(
responseJson => {
console.log(responseJson);
this.setState({ details: responseJson });
},
() => {
console.log(this.state.details);
}
)
.catch(error => {
console.error(error);
});
}
public render() {
const { details } = this.state;
console.log(details);
console.log(details[0]);
The console.log(details[0]) returns
{id: 1, job_id: 1, company_profile: "Sales and Marketing", company_about: "Established in 1992 , it is a renouned marketing company", company_product: "Ford,Mustang,Beetle", …}
But why does console.log(details[0].company_profile) return undefined???
The Error it gives is :
TypeError: Cannot read property 'company_about' of undefined
can anyone help??
Use a conditional statement in your render so that if your request isn't complete and your state doesn't have details yet it doesn't load anything.
Edit --- Sample Code (not your application, but concept of what I mean)
import React, { Component, Fragment } from 'react';
export class App extends Component {
constructor(){
super()
this.state = {
data: [],
isLoading: true
}
}
componentWillMount(){
this.fetchDetails()
}
fetchDetails = () =>{
fetch('/some/url')
.then(res => res.json())
.then( => {
this.setState({data, isLoading: false})
})
}
render() {
return (
<Fragment>
{!this.state.isLoading && <ChildComponent data={this.state.data}} />}
</Fragment>
);
}
}
Try more logging, e.g.:
public getJobDetails = (jobid: number) => {
const JobId = jobid;
fetch('http://127.0.0.1:8000/api/jobs/detail/' + JobId)
.then(response => response.json())
.then(
responseJson => {
console.log(`Fetch resulted in ${JSON.stringify(responseJson)}`);
this.setState({ details: responseJson });
},
() => {
// This line is supposed to act as error handler, but there is no error handling
// See this - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then#Syntax
console.log(this.state.details);
}
)
.catch(error => {
console.error(`Fetch resulted in error ${JSON.stringify(error)}`);
});
}
public render() {
const { details } = this.state;
console.log('Rendering...');
console.log(`step 1. ${JSON.stringify(details)}`);
// let's see if details are not undefined and try next level
details && console.log(`step 2. ${JSON.stringify(details[0])}`);
Your fetch code is asynchronous and you don't have a default value set for this.state You can try a couple different options. You could redefine getJobDetails to return the promise rather than changing the state:
class MyComponent extends React.Component {
public getJobDetails = (jobid: number) => {
const JobId = jobid;
return fetch('http://127.0.0.1:8000/api/jobs/detail/' + JobId)
}
public render() {
this.getJobDetails().then(response => {console.log(response[0])})
}
}
Or you can set a default state
class MyComponent extends React.Component {
public state = {
details: [...]
}
}
EDIT
Performing a network request every render cycle is not very efficient, so it's probably not the best route to go. I also forgot a third option, conditional rendering like this:
class MyComponent extends React.Component {
state = { loading: true }
getJobDetails = (jobid: number) => {
fetch(...).then((response) => {
this.setState({details: response})
this.setState({loading : false})
})
}
render() {
return this.state.loading ? <h1>Loading...</h1> : <div>{this.state.deatils}</div>
}
}
Also you should not be converting your data to JSON if you want to access it as an Object

Bug in mapStateToProps() from fetching json object in Redux

I'm trying to fetch data from my Express server in Redux, and mapping over the object to just use one array, called "vitamins". This is the json object.
router.get('/', function(req, res, next) {
vitamins: [
{
name: "Vitamin B2"
}
],
minerals: [
{
name: "Zinc"
}
]});
});
This is my action.js, where I'm creating the function fetchVitamins() to just fetch micros.vitamins.
export function fetchVitamins() {
return dispatch => {
return fetch("/users")
.then(res => res.json())
.then(micros => {
dispatch(fetchVitaminsSuccess(micros.vitamins));
return micros.vitamins;
})
};
}
export const FETCH_VITAMINS_SUCCESS = 'FETCH_VITAMINS_SUCCESS';
export const fetchVitaminsSuccess = vitamins => ({
type: FETCH_VITAMINS_SUCCESS,
payload: { vitamins }
});
This is my reducers.js
const initialState = {
micros: [],
};
function vitaminReducer(state = initialState, action) {
switch(action.type) {
case FETCH_VITAMINS_SUCCESS:
return {
...state,
micros: action.payload.vitamins
};
default:
return state;
}
}
This is my React component Vitamins.js where I'm importing fetchVitamins() and trying to pass the names of each vitamins to a menu dropdown in an option tag.
componentDidMount() {
this.props.dispatch(fetchVitamins());
}
renderData() {
const { vitamins } = this.state.micros;
return vitamins.map((micro, index) => {
return (
<option value={micro.value} key={index}>{micro.name}</option>
)
})
}
render() {
return (
<select value={this.props.value}>
{this.renderData()}
</select>
)
}
const mapStateToProps = state => ({
micros: state.micros.vitamins,
});
Right now when it renders, I get this error: "TypeError: Cannot read property 'vitamins' of undefined", highlighting over "micros: state.micros.vitamins,".
Am I calling and setting state correctly? If I set my initialState to micros: [], then setting the state to "state.micros.vitamins" should work, I thought.
because of you get the server data n vitamins objects so that data should be in vitamins:[], in that Format so that why state.macros.vitamins work.