link to GitHub project: https://github.com/jkey774/codecademy-ravenous
I have been trying for a few days now to add a new feature to my little app that displays the total number of results for businesses retrieved from a Yelp API call. I can console.log(jsonResponse.total) just before mapping each business but am unsure how to set this up in the return statement to where jsonResponse.total from Yelp.js can be accessed in App.js to do something like setState({ total: total }). Do I need to make a separate API call just to get the total?
here is an example of what the response body looks like:
{
"total": 8228,
"businesses": [
{
"rating": 4,
"id": "E8RJkjfdcwgtyoPMjQ_Olg",
"review_count": 1738,
"name": "Four Barrel Coffee",
"image_url": "http://s3-media2.fl.yelpcdn.com/bphoto/MmgtASP3l_t4tPCL1iAsCg/o.jpg",
"location": {
"city": "San Francisco",
"state": "CA",
"address1": "375 Valencia St",
"zip_code": "94103"
}
},
// ...
]
}
in my Yelp.js file:
const Yelp = {
search(term, location, sortBy) {
const limit = 21;
return fetch(`https://cors-anywhere.herokuapp.com/https://api.yelp.com/v3/businesses/search?term=${term}&location=${location}&sort_by=${sortBy}&limit=${limit}`, {
headers: {
Authorization: `Bearer ${apiKey}`
}
}).then(function (response) {
return response.json();
}).then(function (jsonResponse) {
if (jsonResponse.businesses) {
return jsonResponse.businesses.map(function (business) {
return {
id: business.id,
imageSrc: business.image_url,
name: business.name,
address: business.location.address1,
city: business.location.city,
state: business.location.state,
zipCode: business.location.zip_code,
category: business.categories[0].title,
rating: business.rating,
reviewCount: business.review_count
};
});
}
});
}
};
export default Yelp;
in my App.js file
import React from 'react';
import BusinessList from './components/BusinessList/BusinessList';
import SearchBar from './components/SearchBar/SearchBar';
import Yelp from './util/Yelp';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
total: 0,
businesses: []
}
this.searchYelp = this.searchYelp.bind(this);
}
searchYelp(term, location, sortBy) {
Yelp.search(term, location, sortBy).then((businesses) => {
this.setState({
businesses: businesses
})
})
}
render() {
return (
<div className="App">
<h1>ravenous</h1>
<SearchBar searchYelp={this.searchYelp} />
<BusinessList businesses={this.state.businesses} />
</div>
);
}
}
export default App;
Welcome to Stack Overflow. As you mentioned, you can set multiple keys in a single call to setState, so all you have to do is get the total to your App.js.
In Yelp.js you need to return the total along with the list of businesses. You could do something like:
if (jsonResponse.businesses) {
return {
total: jsonResponse.total,
businessList: jsonResponse.businesses.map(function (business) {
// ... same code as you have before
Then, rework your setState just a little bit in App.js:
Yelp.search(term, location, sortBy).then((businessData) => {
this.setState({
businesses: businessData.businessList,
total: businessData.total
})
})
Related
import React from 'react';
import axios from 'axios';
class Quiz extends React.Component {
constructor(props) {
super(props);
this.state = {
showInstruction: true,
questionIndex: 0,
isLoading: true,
questions: ''
};
}
proceedHandler = () => {
this.setState({
showInstruction: false
})
}
handleQuestion = (event) => {
event.preventDefault();
console.log('show next question');
}
componentDidMount() {
console.log("After mount! Let's load data from API...");
axios({
method: "GET",
url: "/apis/questions"
}).then(response => {
console.log(response.data);
this.setState({ questions: response.data });
this.setState({ isLoading: false });
});
}
render() {
if (this.state.showInstruction) {
return (
<div>
<h1>Welcome to Quiz</h1>
<p>Quiz instructions goes here</p>
<button type="button" onClick={this.proceedHandler}>Proceed</button>
</div>
)
}
const { isLoading, questions } = this.state;
console.log(this.state['questions'][0]);
console.log(questions[0]);
if (isLoading) {
return <div className="App">Loading...</div>;
}
return (
<div>
<form onSubmit={this.handleSubmit}>
<div onChange={this.onChangeValue}>
{/* {questions[0]} */}
</div>
<button onClick={this.handleQuestion}>Next</button>
</form>
</div>
)
}
}
export default Quiz;
My sample API content looks like the below. Right now making the api call to local file which is stored inside Public folder. Path is public/apis/questions.
[
{
id: 0,
question: `What is the capital of Nigeria?`,
options: [`New Delhi`, `Abuja`, `Aba`, `Onisha`],
answer: `Abuja`
},
{
id: 1,
question: `What is the capital of India?`,
options: [`Punjab`, `Awka`, `Owerri`, `Enugu`],
answer: `New Delhi`
}
]
I am building a quiz app and above is my code. I try to fetch the questions from api and render them one by one based on state. I am using axios to fetch the data inside componentDidMount and I can see the this.state.questions is updated with the questions array. But when I do questions[0] or this.state.questions[0], it always returns [. Any help would be greatly appreciated as I am fairly new the react development.
The issue is from my API data. I missed to wrap the keys with double quotes.
Updating the data from api call resolved my issue. So the sample api data will look like the below.
[
{
"id": 0,
"question": "What is the capital of Nigeria?",
"options": [
"New Delhi",
"Abuja",
"Aba",
"Onisha"
],
"answer": "Abuja"
},
{
"id": 1,
"question": "What is the capital of India?",
"options": [
"Punjab",
"Awka",
"Owerri",
"Enugu"
],
"answer": "New Delhi"
}
]
Goal:
Display the content of listGetAllIndustry in frontend.
Problem:
"Error: Objects are not valid as a React child (found: object with keys {listGetAllJobAdvertisement, listGetAllLocation, listGetAllIndustry}). If you meant to render a collection of children, use an array instead."
What part of the code am I missing in order to display the content of listGetAllLocation at frontend?
Info:
*I'm new in React JS
Thank you!
{"listGetAllJobAdvertisement":[],"listGetAllLocation":[{"locationId":1,"city":"LOS ANGELES","country":"USA"},{"locationId":2,"city":"LONDON","country":"ENGLAND"},{"locationId":3,"city":"BERLIN","country":"GERMANY"}],"listGetAllIndustry":[{"industryId":1,"name":"ENERGY"},{"industryId":2,"name":"MATERIALS"},{"industryId":3,"name":"INDUSTRIALS"},{"industryId":4,"name":"CONSUMER STAPLES"},{"industryId":5,"name":"HEALTH CARE"},{"industryId":6,"name":"FINANCIALS"},{"industryId":7,"name":"INFORMATION TECHNOLOGY"},{"industryId":8,"name":"COMMUNICATION SERVICES"},{"industryId":9,"name":"UTILITIES"},{"industryId":10,"name":"REAL ESTATE"}]}
import { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import { VacantPositions } from '../../src/contexts/api';
class Open extends Component {
state = { aaa: [] };
componentDidMount() {
fetch(VacantPositions)
.then(results => results.json())
.then(data => this.setState({ aaa: data } ))
.catch(err => console.log(err))
}
render() {
return (
<div>
{ this.state.aaa}
</div>
);
}
}
export default Open;
You see this error since you are directly using state variable aaa in render function's return statement without telling react how to convert the aaa variable into JSX.
I have included aaa and and 1 more variable bbb. Depending upon what you want you can keep 1 variable remove the other one and its corresponding usage from your Open component.
import { Component } from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class Open extends Component {
state = {
// state variable should be object if api response is object
aaa: {},
// if you only store 'listGetAllIndustry' then state variable should be array
bbb: []
};
componentDidMount() {
// I am assuming the api response to be this
const data = {
listGetAllJobAdvertisement: [],
listGetAllLocation: [
{ locationId: 1, city: "LOS ANGELES", country: "USA" },
{ locationId: 2, city: "LONDON", country: "ENGLAND" },
{ locationId: 3, city: "BERLIN", country: "GERMANY" }
],
listGetAllIndustry: [
{ industryId: 1, name: "ENERGY" },
{ industryId: 2, name: "MATERIALS" },
{ industryId: 3, name: "INDUSTRIALS" },
{ industryId: 4, name: "CONSUMER STAPLES" },
{ industryId: 5, name: "HEALTH CARE" },
{ industryId: 6, name: "FINANCIALS" },
{ industryId: 7, name: "INFORMATION TECHNOLOGY" },
{ industryId: 8, name: "COMMUNICATION SERVICES" },
{ industryId: 9, name: "UTILITIES" },
{ industryId: 10, name: "REAL ESTATE" }
]
};
// fetch(VacantPositions)
// .then(results => results.json())
// .then(data => this.setState({ aaa: data } ))
// .catch(err => console.log(err))
this.setState({
// keeping complete api response in the state
aaa: data || {},
// keeping only 'listGetAllIndustry' from api response in the state
bbb: data.listGetAllIndustry || []
});
}
render() {
return (
<div>
{this.state.aaa.listGetAllIndustry &&
this.state.aaa.listGetAllIndustry.map((industry) => {
return (
<div key={industry.industryId}>
<span>{industry.industryId}.</span>
<span>{industry.name}</span>
</div>
);
})}
===================================
{this.state.bbb.map((industry) => {
return (
<div key={industry.industryId}>
<span>{industry.industryId}.</span>
<span>{industry.name}</span>
</div>
);
})}
</div>
);
}
}
export default Open;
Your api is returning objects with multiple key and values you're setting that object into the state called 'aaa' , so you can't directly render a object in the return part you can render only particular value in the return method . You can use object.entries.map
{Object.keys(this.state.aaa).map(function(key, index) {
return (
<p>{key}</p>
<p>{index}</p>
)
})};
or you can specify the particular value like
render() {
return (
<div>
{ this?.state?.aaa?.listGetAllLocation[0]?.city}
</div>
);}
I'm currently learning how to use apollo client as for a graphql API exposed via graphene-django's DjangoObjectType node. Here's an example
I define a node
class CompanyNode(DjangoObjectType):
class Meta:
model = Company
filter_fields = {
'domain': ['exact'],
'name': ['exact', 'icontains', 'istartswith']
}
interfaces = (graphene.relay.Node, )
class Query(graphene.ObjectType):
companies = DjangoFilterConnectionField(CompanyNode)
A typical query looks like this
query queryCompanies {
companies {
edges {
node {
id
name
__typename
}
}
}
}
And the response is
{
"data": {
"companies": {
"edges": [
{
"node": {
"id": "Q29tcGFueU5vZGU6MQ==",
"name": "great",
"__typename": "CompanyNode"
}
},
{
"node": {
"id": "Q29tcGFueU5vZGU6MTI=",
"name": "awesome",
"__typename": "CompanyNode"
}
},
]
}
}
}
I'm using apollo client with react for the frontend and my queries are returning okay. A typical component looks like this.
To initialize some state in index.js I'm writing the companies data to the cache.
const cache = new InMemoryCache();
cache.writeData({
data: {
companies: {
edges: [],
typename: 'CompanyNodeConnection',
__typename: 'CompanyNodeConnection',
},
},
});
Then in my component, I'm reading from my cache like below.
import React from 'react';
import { useQuery, useApolloClient } from '#apollo/react-hooks';
const Companies = () => {
const root = useApolloClient().cache.data.data;
const QUERY_ALL_COMPANIES = gql`
query getCompanies {
companies {
edges {
node {
id
name
}
}
}
}
`;
const { loading, error } = useQuery(QUERY_ALL_COMPANIES);
if (error) {
return <p>{JSON.stringify(error?.graphQLErrors[0]?.message)}</p>;
}
return (
<div>
<h2>Companies</h2>
{loading ? (
<p>loading</p>
) : (
<div>
{root['$ROOT_QUERY.companies'].edges.map((com) => {
const { id: edgeKey } = com;
const {
node: { id: itemNodeId },
} = root[edgeKey];
const { id, name } = root[itemNodeId];
return (
<div key={id}>
{name}
</div>
);
})}
</div>
)}
</div>
);
};
export default Companies;
Now my question is, is this the proper way to initialise this state? Secondly, is this the proper way of reading this particular query from the cache?
I'd like to see other patterns and opinions on what works. I'm thinking this pattern of reading state is too brittle.
i am working on autocomplete with reactjs and react material-ui. Now its working on only one field name symbol but i want its work on multiple fields name like "symbol and name" Here is my working code and API response. API response filed name return row.symbol;
React search code
import React, { Component } from "react";
import Autocomplete from "./Autocomplete";
import { render } from "react-dom";
import ApiService from "../../service/ApiService";
const style = {
flexGrow: 1,
};
export class SearchScripComponent extends Component<any, any> {
constructor(props: any) {
super(props);
this.state = {
searchArray: [],
message: null,
};
this.searchScripData = this.searchScripData.bind(this);
}
componentDidMount() {
this.searchScripData(this.requesDATA2());
}
requesDATA2() {
let data1 = { symbolOrName: "TATA" };
return data1;
}
searchScripData(searchScrip: any) {
ApiService.searchScripDataList(searchScrip).then((res) => {
this.setState({ searchArray: res.data.data });
});
}
render() {
const suggestions = this.state.searchArray.map((row: any) => {
return row.symbol;
});
return <Autocomplete suggestions={suggestions} />;
}
}
export default SearchScripComponent;
API Data
{
"statusCode": 200,
"message": "SUCCESS",
"data": [
{
"scripId": 299,
"symbol": "TATAGLOBAL",
"name": "abc"
},
{
"scripId": 520,
"symbol": "TATAYODOGA",
"name": "ttp"
},
{
"scripId": 1195,
"symbol": "TATASPONGE",
"name": "eer"
},
{
"scripId": 30,
"symbol": "TATASTLBSL",
"name": "qwer"
}
]
}
I'm having difficulties fetching data from an API in a React app with a simple standard template for fetching API data. The returned result from the console logs are blank arrays.
import React, {Component} from 'react';
import './App.css';
import Chart from './components/chart'
const API_URL = "http://ergast.com/api/f1/2016/1/results.json";
class App extends Component {
constructor(props) {
super(props)
this.state = {
results: [],
};
}
componentDidMount() {
fetch(API_URL)
.then(response => {
if (response.ok) {
return response.json()
}
else {
throw new Error ('something went wrong')
}
})
.then(response => this.setState({
results: response.MRData
})
)}
render() {
const {results} = this.state;
return (
<div className="App">
<Chart data={results}/>
</div>
);
}
}
export default App;
chart.js
import React from 'react';
import {XYPlot, XAxis, YAxis, VerticalGridLines, HorizontalGridLines, LineSeries} from 'react-vis';
const Chart = (props) => {
console.log(props.data);
const dataArr = props.data.map((d)=> {
return {x: d.RaceTable.Results.Driver.driverId, y: d.RaceTable.Results.position}
});
console.log(dataArr);
return (
<XYPlot
xType="ordinal"
width={1000}
height={500}>
<VerticalGridLines />
<HorizontalGridLines />
<XAxis title="Driver" />
<YAxis title="Race Finish Position" />
<LineSeries
data={dataArr}
style={{stroke: 'violet', strokeWidth: 3}}/>
</XYPlot>
);
}
export default Chart;
Really cannot figure out where I have gone wrong. I have set the state correctly with results: response.MRData isn't it? (MRData is the key of the JSON.) This is the structure of the json. API Link: http://ergast.com/api/f1/2016/1/results.json
JSON Example Response
{
"MRData": {
"xmlns": "http://ergast.com/mrd/1.0",
"RaceTable": {
"Races": [
{
"season": "2008",
"round": "1",
}
},
"Results": [
{
"position": "1",
"Driver": {
"driverId": "hamilton",
"permanentNumber": "44",
"code": "HAM",
"url": "http://en.wikipedia.org/wiki/Lewis_Hamilton",
"givenName": "Lewis",
"familyName": "Hamilton",
"dateOfBirth": "1985-01-07",
"nationality": "British"
},
}
},
.
.
.
]
}
]
}
}
}