facing error of bad request even thought the query is same - javascript

Well i am trying to reduce the line of code at once refactoring the code
import React, { Component } from 'react';
import { Loader } from '../../components';
import './ProductListing.scss';
import { ProductCard } from '../../components';
import { productQuery } from '../../utls/queries';
export class ProductListing extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
products: [],
categoryId: '',
};
}
componentDidMount() {
const currentUrl = window.location.pathname;
const id = currentUrl.replace('/', '');
this.setState({ categoryId: id });
const newQuer = { ...productQuery };
const query = `
query{
categories {
name
products {
id,
name,
brand,
inStock,
gallery,
category,
prices {
amount,
currency {
label,
symbol
}
}
}
}
}
`;
console.log(query === productQuery);
console.log(productQuery);
fetch('http://localhost:4000', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify({
query,
}),
})
.then((response) => {
return response.json();
})
.then((data) => {
this.setState({
products: data.data,
loading: false,
});
});
}
render() {
if (this.state.loading === true) {
return <Loader />;
} else {
return (
<div>
<h2 className='page__listing__title'>
{this.state.categoryId[0].toUpperCase() +
this.state.categoryId.substring(1)}
</h2>
<div className='productlisting__page'>
{this.state.products.categories.map((item, index) => (
<div key={index}>
{item.name === this.state.categoryId ? (
<div className='product__listing__card'>
{item.products.map((product, i) => (
<ProductCard product={product} key={i} />
))}
</div>
) : (
''
)}
</div>
))}
</div>
</div>
);
}
}
}
export default ProductListing;
In the process of reducing code i see that the query is taking a lot of places so i decided to write it at separate place now i am importing it as productQuery when i console.log(productQuery===query) it says true but the place where i am using the query to fetch data i use productQuery it just give bad error i cant understand ...
if some one have much better idea i really like if you can suggest me much better ways by which i can reduce the lines of code

I think what's happening is you're accidentally destructuring the query you import, when you say
const newQuery = {...productQuery}
productQuery is simply a string (as proven by your console log that stays productQuery === query).
newQuery is an object that destructures the string, and trying to use that would likely result in a failure.

Related

TypeError: this.state.data.map in reactjs

class Home extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoaded: false,
};
}
componentDidMount() {
fetch("https://reqres.in/api/users?page=2")
.then((res) => res.json())
.then((json) => {
this.setState({
isLoaded: true,
data: json,
});
});
}
render() {
var { isLoaded, data }= this.state;
if(!isLoaded){
return<div>Is isLoaded</div>
}
else{
return (
<div>
<ul>
{() =>
this.state.data.map((data, index) => (
<li key={index}>Email: {data.email}</li>
))
}
;
</ul>
</div>
);
}
}
}
export default Home;
Hii All , I know this question is asked many times but I cant figure it out I'am getting the error. I have checked for all the questions similar to this but haven't found specific solution if I use another link i.e, "https://jsonplaceholder.typicode.com/users" this one the code works fine .
The returned data from https://reqres.in/api/users?page=2 is not an array, but an object with a data property containing what you are looking for (an array). The result of the request is :
{"page":1,"per_page":6,"total":12,"total_pages":2,"data":[{"id":1,"email":"george.bluth#reqres.in","first_name":"George","last_name":"Bluth","avatar":"https://reqres.in/img/faces/1-image.jpg"},{"id":2,"email":"janet.weaver#reqres.in","first_name":"Janet","last_name":"Weaver","avatar":"https://reqres.in/img/faces/2-image.jpg"},{"id":3,"email":"emma.wong#reqres.in","first_name":"Emma","last_name":"Wong","avatar":"https://reqres.in/img/faces/3-image.jpg"},{"id":4,"email":"eve.holt#reqres.in","first_name":"Eve","last_name":"Holt","avatar":"https://reqres.in/img/faces/4-image.jpg"},{"id":5,"email":"charles.morris#reqres.in","first_name":"Charles","last_name":"Morris","avatar":"https://reqres.in/img/faces/5-image.jpg"},{"id":6,"email":"tracey.ramos#reqres.in","first_name":"Tracey","last_name":"Ramos","avatar":"https://reqres.in/img/faces/6-image.jpg"}],"support":{"url":"https://reqres.in/#support-heading","text":"To keep ReqRes free, contributions towards server costs are appreciated!"}}
So you cannot use map function, which is from the Array prototype, on the result of your request. You must access the data property first :
this.state.data.data.map((data, index) => ( // note the double data
<li key={index}>Email: {data.email}</li>
))
You could also assign json.data to the state.data to avoid the ugly .data.data :
this.setState({
isLoaded: true,
data: json.data, // note the .data
});
I think the problem is in brackets around your .map() method. Please try this
class Home extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoaded: false,
};
}
componentDidMount() {
fetch("https://reqres.in/api/users?page=2")
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
data: json,
});
});
}
render() {
const { isLoaded, data } = this.state;
if (!isLoaded) {
return <div>Is isLoaded</div>;
} else {
return (
<div>
<ul>
{data?.map((data, index) => {
return <li key={index}>Email: {data.email}</li>;
})}
</ul>
</div>
);
}
}
}
export default Home;
I don't see any error, it's working just fine.
Output:
Working Example: StackBlitz
import * as React from 'react';
import { Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoaded: false,
};
}
componentDidMount() {
fetch('https://reqres.in/api/users?page=2')
.then((res) => res.json())
.then((json) => {
console.log(json.data);
this.setState({
isLoaded: true,
data: json.data,
email: null,
});
});
}
render() {
var { isLoaded, data } = this.state;
if (!isLoaded) {
return <div>Is isLoaded</div>;
} else {
return (
<div>
<div className="contents home">
<img
src="https://trucard.io/india/wp-content/uploads/2021/08/2021-June-TruCard-Logo.png
"
width={50}
alt="img"
className="trucard-img"
/>
</div>
<div className="button">
<button className="button-button">Load list</button>
</div>
<ul>
{this.state.data?.map((data, index) => (
<li key={index}>Email: {data.email}</li>
))}
;
</ul>
</div>
);
}
}
}
export default App;

Why is one of my child components able to get handleClick() but the others are not?

PROBLEM
I am swapping components based on state in Dashboard(parent) component and passing props to all of them. When I log in using wholesaler the app is running without problems but when i log in with retailer account the app return
TypeError: this.props.handleClick is not a function
when i click on a button-handleClick() -> switch components through handleClick which changes state
My components are almost identical and i have no idea where this is coming from.
Thank you in advance! :)
Files:
Dashboard.js
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { Retailers } from './_components/Retailers'
import { Locations } from './_components/Locations'
import { Products } from './_components/Products'
class Dashboard extends Component {
constructor(props) {
super(props)
this.state = {
chosenRetailerId: null,
chosenLocationId: null,
mountComponent: ''
}
this.handleClick = this.handleClick.bind(this)
}
componentDidMount() {
switch (this.props.user.type) {
case 'wholesaler':
this.setState({ mountComponent: "retailers" })
break;
case 'retailer':
this.setState({ mountComponent: "locations" })
break;
case 'location':
this.setState({ mountComponent: "products" })
break;
default:
break;
}
}
handleClick(id, shouldMountComponent) {
switch (shouldMountComponent) {
case 'locations':
this.setState({
mountComponent: shouldMountComponent,
chosenRetailerId: id
})
break;
case 'products':
this.setState({
mountComponent: shouldMountComponent,
chosenLocationId: id
})
break;
default:
break;
}
}
render() {
const { user } = this.props
const { chosenLocationId, chosenRetailerId, mountComponent } = this.state
return (
<div className="dashboard">
{user.type === 'wholesaler' &&
<div className="wholesaler">
<h1>Wholesaler</h1>
<h3>{user._id}</h3>
{this.state.mountComponent === 'retailers' &&
<Retailers mountComponent={mountComponent} handleClick={this.handleClick} />
}
{this.state.mountComponent === 'locations' &&
<Locations retailerId={chosenRetailerId} locationId={chosenLocationId} mountComponent={mountComponent} handleClick={this.handleClick} />
}
{this.state.mountedComponent === 'products' &&
<Products locationId={chosenLocationId} mountComponent={mountComponent}/>
}
</div>
}
{user.type === 'retailer' &&
<div className="retailers">
<h1>Retailer {user._id}</h1>
<Locations locationId={chosenLocationId}/>
</div>
}
{user.type === 'location' &&
<div className="locations">
<h1>Location {user._id}</h1>
<Products />
</div>
}
<p>You're logged in with React & JWT!!</p>
<p>
<Link to="/login">Logout</Link>
</p>
</div>
)
}
}
function mapStateToProps(state) {
const { authentication } = state
const { user } = authentication
return {
user
}
}
const connectedDashboard = connect(mapStateToProps)(Dashboard)
export { connectedDashboard as Dashboard }
Retailers.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
class Retailers extends Component {
state = {
retailers: []
}
componentDidMount() {
const { user } = this.props
const requestOptions = {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + user.token }
}
fetch(`http://localhost:4000/retailers/by-wholesaler/${user._id}`, requestOptions)
.then(result => result.json())
.then(result => {
this.setState({
retailers: result
})
})
}
render() {
const { retailers } = this.state
return (
<div className="retailers">
{retailers.map((retailer, index) =>
<button key={index} onClick={() => this.props.handleClick(retailer._id, 'locations')}>{retailer.name}</button>
)}
</div>
)
}
}
function mapStateToProps(state) {
const { authentication } = state
const { user } = authentication
return { user }
}
const connectedRetailers = connect(mapStateToProps)(Retailers)
export { connectedRetailers as Retailers }
Locations.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
class Locations extends Component {
state = {
locations: []
}
componentDidMount() {
const { user } = this.props
const requestOptions = {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + user.token }
}
const retailerId = (user.type === 'retailer') ? user._id : this.props.retailerId
console.log(retailerId)
fetch(`http://localhost:4000/locations/by-retailer/${retailerId}`, requestOptions)
.then(result => result.json())
.then(result => {
this.setState({
locations: result
})
})
}
render() {
const { locations } = this.state
return (
<div className="locations">
{locations.map((location, index) =>
<button key={index} onClick={() => this.props.handleClick(location._id, 'products')}>{location.name}</button>
)}
</div>
)
}
}
function mapStateToProps(state) {
const { authentication } = state
const { user } = authentication
return { user }
}
const connectedLocations = connect(mapStateToProps)(Locations)
export { connectedLocations as Locations }
You have to pass handleCLick to location as a prop. You do that in you wholesaler case (passing it to the retailer component), but not when using the Locations component
You didn't pass handleClick as a prop :)
<Retailers handleClick={this.handleClick} />
<Locations handleClick={this.handleClick} />
So prop is undefined and you can't call it as a function.
Check the locations.map function in your Locations.js.
Your are passing a so called thisArg to the map function, so it is no longer using the right context.
This should work:
<div className="locations">
{locations.map((location, index) =>
<button key={index} onClick={() =>
this.props.handleClick(location._id, 'products')}>
{location.name}
</button>
)}
</div>
Also, think about using the uuid package for your iteration keys. Now you are using an index and that will not be unique if you do so in another iteration too (not the case yet so).

Retrieving Array from API and filtering through in React

I have successfully called and passed the token to my API endpoint. However, I do not need both objects. I just want to work with the first index in the array that has fields. So I would like to retrieve all the details and print them out in the browser but for now all what can be printed is ID and type
I have tried filtering through the data array but it did not work.
var config = {
headers: {'Authorization': 'Bearer token'}
};
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
data: [],
}
}
componentDidMount() {
axios.get('https://api.transferwise.com/v1/profiles',config)
.then(response => {
if (response.status === 200 && response != null) {
this.setState({
data: response.data
});
} else {
console.log('problem');
}
})
.catch(error => {
console.log(error);
});
}
render() {
const { data } = this.state;
return (
<div >
{this.state.data.map(object => (
<p key={object.uid}>{object.id} {object.type}</p>
))}
</div>
)
}};
export default App;
Looks like your data consists of an array where each item can be an object with details of a different type.
To dynamically render the field values of each object you could do something like:
{this.state.data.map(({ id, type, details }) => {
return (
<>
<p key={id}>
{id} {type}
</p>
{Object.keys(details).map((key, index) => (
<p key={index}>{details[key]}</p>
))}
</>
);
})}
So it looks to me like you're not going deep enough in your mapped object.
which means you should access the details portion of the object to get the info you want
this.state.data.map(object => (
// The object data structure at this point should look like this
// {
// details: {firstName: 'firstExample', lastName: 'lastExample', ...},
// id: 'example'
// type: 'personal'
// } if you console.log(object) you should be able to see it
{<p key={object.details.id}>{object.details.id} {object.details.type}</p>
))}

render method being called before API data is loaded in React

Total beginner with React.
I am trying to work out the standard approach to this situation in React.
I am accessing an api, the data is being returned all ok, except I am trying to set the data as a state of my component, and the render() method is referencing the state before any data is returned so the state property is being defined as 'null'.
In my code sample below you can see I am logging to the console, and despite the order of things, the second log is being returned from the browser before the one that has setState to be the API data.
Any help / explanation as to why this is happening despite using .then() would be appreciated.
Thank you.
PS: I have removed the TeamList component for simplification, but like the 'second log', the component gets rendered before the data has actually been pulled in.
import React, { Component } from 'react';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: null,
}
}
componentDidMount() {
const uri = 'http://api.football-data.org/v2/competitions/PL/teams';
let h = new Headers()
h.append('Accept', 'application/json')
h.append('X-Auth-Token', 'XXXXXXXXXXXXXXXXXXXX')
let req = new Request(uri, {
method: 'GET',
headers: h,
mode: 'cors'
})
var component = this;
fetch(req)
.then( (response) => {
return response.json()
})
.then( (json) => {
this.setState({ data: json })
})
.then( (json) => {
console.log( 'second log', this.state.data )
})
.catch( (ex) => {
console.log('parsing failed', ex)
})
console.log( 'first log', this.state.data )
}
render() {
return (
<div>
<div className="App">
<TeamList list={this.state.data} />
</div>
</div>
);
}
}
export default App;
You need to add something like this to the start of your render():
if (this.state.data === null) {
return false;
}
So your code should be:
render() {
if (this.state.data === null) {
return false;
}
return (
<div>
<div className="App">
<TeamList list={this.state.data} />
</div>
</div>
);
}
render() is called immediately, but you want it to return false until this.state.data has data
When you mount a component, it gets rendered immeadiately with the initial state (that you've set in the constructor). Then later, when you call setState, the state gets updated and the component gets rerendered. Therefore it makes sense to show something like "loading..." until state.data is not null:
render() {
return (
<div>
<div className="App">
{this.state.data ? <TeamList list={this.state.data} /> : "loading..." }
</div>
</div>
);
}
Now additionally logging does not work as expected as setState does not return a promise, so:
.then( (json) => {
this.setState({ data: json })
})
.then( (json) => {
console.log( 'second log', this.state.data )
})
is actually the same as:
.then( (json) => {
this.setState({ data: json })
console.log( 'second log', this.state.data )
})
and that still logs null as setState is asynchronous, which means that calling it does not change this.state now but rather somewhen. To log it correctly use the callback:
then( (json) => {
this.setState({ data: json }, () => {
console.log( 'second log', this.state.data )
});
})
Just an idea:
import React, { Component } from 'react';
class App extends Component {
constructor(props)
{
super(props);
this.state = {
data: null,
};
}
componentDidMount()
{
fetch('http://api.football-data.org/v2/competitions/PL/teams')
.then(response => response.json())
.then(data => this.setState({ data }));
}
render() {
return (
<div>
<div className="App">
<TeamList list={this.state.data} />
</div>
</div>
);
}
}
export default App;
TeamList :
class TeamList extends React.Component {
constructor(props) {
super(props);
}
render(){
return (
<ul>
{
this.props.list.map((element, i) => {
return (
<li className="un-res t_d " key={i}>{element}</li>
)
}
})
}
}
export default TeamList
Happy coding!

How to set the background image for a div in React?

I'm creating a react application, and I have a component that is define more or less like this:
import React, { Component } from 'react';
import axios from 'axios';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
loading: true,
error: null
};
}
componentDidMount() {
var _this = this;
this.serverRequest =
axios
.get("LinkToAPI")
.then(result => {
_this.setState({
data: result.data,
loading: false,
error: null
});
})
.catch(err => {
_this.setState({
loading: false,
error: err
});
});
}
componentWillUnmount() {
this.serverRequest.abort();
}
renderLoading() {
return <div>Loading...</div>
}
renderError() {
return (
<div>
Something when wrong: {this.state.error.message}
</div>
);
}
renderData() {
const { error, data} = this.state;
if (error) {
return this.renderError();
}
return (
<div>
{data.map(d=> {
if (d.imageUrl) {
<div className="dataDiv" style="background: url('{d.imageUrl}')" key={d.Id}>{d.name}</div>
} else {
<div className="dataDiv" style="background: url('LinkToSomeImage')" key={d.Id}>{d.name}</div>
}
}
)}
</div>
)
}
render() {
return (
<div className="App">
{this.props.loading ? this.renderLoading() : this.renderData()}
</div>
);
}
}
It basically gets the JSON data from the API, and using it renders some divs with the data inside the JSON. I'm applying to the divs containing the data dataDiv class, which is define inside my App.css file. Additionally, I want to set a background image for the div. What exactly I want to do is that if the data entry includes a field named imageUrl I want to use that url as a url to the background image, otherwise, if it is null or empty, I want to use a default url that I found from the internet. What is a proper way to handle this in React? The code segment above doesn't seem to work, especially the if-else statement inside the renderData function. How can I fix this code, or is there any way to handle this more gracefully, probably maybe inside the CSS?
I would do like this
Please make sure to check backgroundUrl equal to your desired CSS.
{data.map(d => {
let backgroundUrl = "LinkToSomeImage";
if (d.imageUrl) {
backgroundUrl = d.imageUrl;
}
return (
<div className="dataDiv" style={{backgroundImage: `url(${backgroundUrl})`}} key={d.Id}>{d.name}</div>
)
})}
EDIT
A full function would be:
renderData() {
const { error, data} = this.state;
if (error) {
return this.renderError();
}
return (
<div>
{data.map(d => {
let backgroundUrl = "LinkToSomeImage";
if (d.imageUrl) {
backgroundUrl = d.imageUrl;
}
return (
<div className="dataDiv" style={{backgroundImage: `url(${backgroundUrl})`}} key={d.Id}>{d.name}</div>
)
})}
</div>
)
}
<Box
onClick={() => {
history.push({
pathname: `/p/c/${data.ProductName.replace(/\//g, "~")}/1`
});
}}
css={{
backgroundImage:`url(${data.imageUrl||"/default-placeholder.png"})`,
backgroundPosition: 'center',
backgroundRepeat: 'no-repeat'
}}
>

Categories

Resources