**
React Gatsby web app: Uncaught SyntaxError: Unexpected token '<'
**
I am getting this error while running the app. This page is having a button event handler. look at this code given below.
Coursecart.js page.
import React, { Component } from "react"
import Heading from "../Reuseable/Heading"
import Img from "gatsby-image"
const getCategory = items => {
let holditems = items.map(items => {
return items.node.category
})
let holdCategories = new Set(holditems)
let categories = Array.from(holdCategories)
categories = ["all", ...categories]
return categories
}
export default class Coursecart extends Component {
constructor(props) {
super(props)
this.state = {
courses: props.courses.edges,
mycourses: props.courses.edges,
mycategories: getCategory(props.courses.edges),
}
}
cateClicked = category => {
let keepItsafe = [...this.state.courses]
if (category === "all") {
this.setState(() => {
return { mycourses: keepItsafe }
})
} else {
let holdMe = keepItsafe.filter(node => {
return node.category === category
})
this.setState(() => {
return { mycourses: holdMe }
})
}
}
render() {
return (
<section className="py-5">
<div className="container">
<Heading title="Courses" />
<div className="row my-3">
<div className="col-10 mx-auto text-center">
{this.state.mycategories.map((category, index) => {
return (
<button
type="button"
className="btn btn-info m-3 px-3"
key={index}
onClick={() => {
this.cateClicked(category)
}}
>
{category}
</button>
)
})}
</div>
</div>
<div className="row">
{this.state.mycourses.map(({ node }) => {
return (
<div
key={node.id}
className="col-11 col-md-6 d-flex my-3 mx-auto"
>
<Img fixed={node.image.fixed} />
<div className="flex-grow-1 px-3">
<div className="d-flex">
<h6 className="mb-0">{node.title}</h6>
<h6 className="mb-0 text-success ml-3">$ {node.price}</h6>
</div>
<p className="text-muted">
<small>{node.description.description}</small>
</p>
<button
className="btn btn-warning snipcart-add-item"
data-item-id={node.id}
data-item-name={node.title}
data-item-price={node.price}
data-item-url="https://https://rgecom.netlify.app/"
data-item-image={node.image.fixed.src}
>
Join Now
</button>
</div>
</div>
)
})}
</div>
</div>
</section>
)
}
}
This is commonly caused by attempting to parse an XHR response as JSON, when the body actually contains HTML.
That is frequently caused when the request is wrong: a misspelled path component or an unsupported method. Some HTTP server frameworks are configured by default to return a very basic HTML error page for unmatched routes.
So, if you've got a typo in your fetch, and the target server is using the default unmatched-route response, but your code assumes the response will be JSON, you will get this exact error.
Try running this snippet in your JS console, and I bet you'll get the same error:
JSON.parse('<!DOCTYPE html>')
Related
I am getting this error
Mainsection.js:27 Uncaught TypeError: Cannot read properties of undefined (reading 'map')
Here is my mainsection.js file, I am using API key to iterate the data, I am still not getting the cause of the error. First I had made an array whose name was info and stored all the data in it and then iterated it, Now after using fetchapi, I deleted that array as it was of no use. I don't know whether it was meant to delete or not.
import React, { Component } from 'react'
import Card from './Card'
export default class Mainsection extends Component {
constructor() {
super();
this.state = {
info:null
}
}
async componentDidMount(){
let Url="https://randomuser.me/api/?inc=gender,name,nat,location,picture,email&results=";
let data= await fetch(Url);
let parsedData= await data.json()
console.log(parsedData);
this.setState({
info : parsedData.info
})
}
render() {
return (
<div>
<div className="container mt-5">
<div className="row">
{this.state.info.map((element) => {
return <div className="col-md-4">
<Card key={element.email} name={element.name} location={element.location} gender={element.gender} imageUrl={element.picture.medium} />
</div>
})}
</div>
</div>
</div>
)
}
}
And here is my card.js file
import React, { Component } from 'react'
export default class Card extends Component {
render() {
let {name, location, gender, imageUrl}=this.props
return (
<div>
<div className="card" style={{ width: "18rem" }}>
<img src={imageUrl} className="card-img-top" alt="..." />
<div className="card-body">
<h5 className="card-title">{name}</h5>
<p className="card-text">{location}</p>
<p className="card-text">{gender}</p>
Go somewhere
</div>
</div>
</div>
)
}
}
Please let me I should provide more details
You can find a working example here: https://codesandbox.io/s/musing-hill-uxtt0
There are other issues with your code. For example, the name and location are objects and you are directly trying to show it on UI. I have also added code to fix name.
Mainsection.js
import React, { Component } from "react";
import Card from "./Card";
export default class Mainsection extends Component {
constructor() {
super();
this.state = {
info: null,
results: null
};
}
async componentDidMount() {
let Url =
"https://randomuser.me/api/?inc=gender,name,nat,location,picture,email&results=";
let data = await fetch(Url);
let parsedData = await data.json();
console.log(parsedData);
this.setState({
info: parsedData.info,
results: parsedData.results
});
}
render() {
console.log("results : ", this.state.results);
return (
<div>
<div className="container mt-5">
<div className="row">
{this.state?.results?.map((element) => {
return (
<div className="col-md-4">
<Card
key={element.email}
name={element.name}
location={element.location}
gender={element.gender}
imageUrl={element.picture.medium}
/>
</div>
);
})}
</div>
</div>
</div>
);
}
}
Card.js
import React, { Component } from "react";
export default class Card extends Component {
render() {
let { name, location, gender, imageUrl } = this.props;
return (
<div>
<div className="card" style={{ width: "18rem" }}>
<img src={imageUrl} className="card-img-top" alt="..." />
<div className="card-body">
<h5 className="card-title">{`${name?.title} ${name?.first} ${name?.last}`}</h5>
<p className="card-text">{JSON.stringify(location)}</p>
<p className="card-text">{gender}</p>
<a href="/" className="btn btn-primary">
Go somewhere
</a>
</div>
</div>
</div>
);
}
}
So, the API you are using doesn't response back with an Array. But it responses with an object, that object has 2 attributes which are results and info. as you can see below
{
"results": ...
....
....
"info": ...
}
and results it self is an Array of objects, while info is just an object.
So yes, you cant use map on object, its only useable on arrays.
Check the response carefully so you can decide what you wanna do.
I'm trying to add a search bar to a parent component.
All the logic is working fine in the console. With every character that is typed in the search field I get fewer results.
I try to pass it to a child component to render the card(s) result, but I get a blank card: I can not see data passed.
Parent Component <AllAssets>
class AllAssets extends Component {
state = {
cards: [],
searchField: '',
}
async componentDidMount() {
const { data } = await cardService.getAllCards();
if (data.length > 0) this.setState({ cards: data });
}
addToFavorites = (cardId, userId) => {
saveToFavorites(cardId, userId)
toast.error("The asset was added to your favorites.")
}
render() {
const { cards, searchField } = this.state;
const user = getCurrentUser();
const filteredAssets = cards.filter(card => (
card.assetName.toLowerCase().includes(searchField.toLowerCase())));
console.log(filteredAssets);
return (
<div className="container">
<SearchBox placeholder={"Enter asset name..."}
handleChange={(e) => this.setState({ searchField: e.target.value })}
/>
<PageHeader>Assets available for rent</PageHeader>
<div className="row">
<div className="col-12 mt-4">
{cards.length > 0 && <p>you can also add specific assets to your favorites and get back to them later...</p>}
</div>
</div>
<div className="row">
{!!filteredAssets.length ? filteredAssets.map(filteredAsset => <SearchResult addToFavorites={this.addToFavorites} filteredAsset={filteredAsset} user={user} key={filteredAsset._id} />) :
cards.map(card => <CardPublic addToFavorites={this.addToFavorites} card={card} user={user} key={card._id} />)
}
</div>
</div >
);
}
}
export default AllAssets;
Child Component <SearchResult>
const SearchResult = (addToFavorites, filteredAsset, card, user) => {
return (
<div className="col-lg-4 mb-3 d-flex align-items-stretch">
<div className="card ">
<img
className="card-img-top "
src={filteredAsset.assetImage}
width=""
alt={filteredAsset.assetName}
/>
<div className="card-body d-flex flex-column">
<h5 className="card-title">{filteredAsset.assetName}</h5>
<p className="card-text">{filteredAsset.assetDescription}</p>
<p className="card-text border-top pt-2">
<b>Tel: </b>
{filteredAsset.assetPhone}
<br />
<b>Address: </b>
{filteredAsset.assetAddress}
</p>
<p>
<i className="far fa-heart text-danger me-2"></i>
<Link to="#" className="text-danger" onClick={() => addToFavorites(card._id, user._id)}>Add to favorites</Link>
</p>
</div>
</div>
</div>
);
}
export default SearchResult;
When I console.log(filteredAsset) in <SearchResult> I get an empty object. What am I doing wrong?
This line is incorrect:
const SearchResult = (addToFavorites, filteredAsset, card, user) => {
You are passing in positional arguments, not named props. Do this instead:
const SearchResult = ({addToFavorites, filteredAsset, card, user}) => {
In your original code, React attaches all of your props as fields on the first argument. So they would be accessible in the child, but not in the way you're trying to access them. Try logging out the values of each of the arguments in the child, if you're curious to see what happens.
The corrected version passes in a single object with field names that match the names of your props. It's shorthand that's equivalent to:
const SearchResult = (
{
addToFavorites: addToFavorites,
filteredAsset: filteredAsset,
card: card,
user: user,
}
) => {
API: https://hn.algolia.com/api/v1/items/12701272
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import React, { useState } from "react";
// import "./index.css";
const Tree = ({ data = []}) => {
return (
<div className="d-tree">
<ul className="d-flex d-tree-container flex-column">
{data.map((tree) => (
<TreeNode node={tree} />
))}
</ul>
</div>
);
};
const TreeNode = ({ node }) => {
const [childVisible, setChildVisiblity] = useState(false);
const hasChild = node.children ? true : false;
return (
<li className="d-tree-node border-0">
<div className="d-flex" onClick={(e) => setChildVisiblity((v) => !v)}>
{hasChild && (
<div
className={`d-inline d-tree-toggler ${
childVisible ? "active" : ""
}`}
>
<FontAwesomeIcon icon="caret-right" />
</div>
)}
<div className="col d-tree-head">
<i className={`mr-1 `}> </i>
{node.text}
</div>
</div>
{hasChild && childVisible && (
<div className="d-tree-content">
<ul className="d-flex d-tree-container flex-column">
<Tree data={node.children} />
</ul>
</div>
)}
</li>
);
};
export default Tree;
I want to show all the comments in tree format,
I tried by above method but it shows error: TypeError: data.map is not a function
The data passed in tree function is the api converted into data.
What to do?
You are getting this error TypeError: data.map is not a function because data is not an array but an object. The response from the API is -
{
id:12701272,
created_at:"2016-10-13T15:15:48.000Z",
created_at_i:1476371748,
type:"story",
author:"fatihky",
title:"Google's “Director of Engineering” Hiring Test",
url:"http://www.gwan.com/blog/20160405.html",
text:null,
points:1764,
parent_id:null,
story_id:null,
children:(190) [...],
options:(0) [...]
}
The comment is inside the the object which is inside the array having children as the key.
I am trying to develop a discussion forum website using React, Node and MongoDB.In post object, there is nested author object and tags array.
Here is sample image of a post object:
here is the component which I am trying to render:
import React, { Component } from "react";
import http from "../services/httpService";
import { postEndPoint, repliesEndPoint } from "../config.json";
class PostPage extends Component {
state = {
post: [],
replies: [],
};
async componentDidMount() {
const id = this.props.match.params.id;
const { data: post } = await http.get(postEndPoint + "/" + id);
const { data: replies } = await http.get(repliesEndPoint + "/" + id);
console.log(post.tags, typeof post.tags);
this.setState({ post: post, replies: replies });
}
render() {
const { post, replies } = this.state;
return (
<React.Fragment>
<div className="container col-lg-8 shadow-lg p-3 mt-5 bg-body rounded">
<h2>{post.title}</h2>
<p className="mt-4" style={{ color: "#505050" }}>
{post.description}
</p>
<div className="mt-1">
Related Topics:
{post.tags.map((tag) => (
<span className="badge badge-secondary m-1 p-2">
{(tag).name}
</span>
))}
<h6 className="mt-2">
{post.upvotes.length} Likes {post.views} Views
</h6>
<div class="d-flex w-100 justify-content-between">
<small class="mb-1">Posted by {post.author['name']}</small>
</div>
</div>
</div>
</React.Fragment>
);
}
}
export default PostPage;
This throws the following : TypeError: post.tags is undefined. a Similar error is throws while accessing post.upvotes and post.author
Since you do your http request in 'componentDidMount' a render occured at least once before. So react tried to read post.something and it was still undefined.
And even if you do it before an http request is asynchronous so be careful
You need to check that post.something is defined before you use.
Also your initialisation if confusing you initialize post as an array but you are trying to do post.title.
If post is really an array then post.map() won't crash on an empty array.
If it's an object check that is it defined correctly.
Try this as initial state
state = {
post: {
description:"",
title:"",
tags: [],
author:[] ,
upvotes:[] ,
views : 0
},
}
initial state for post is {}
state = {
post: { tags: [] },
replies: [],
};
You can have a simple if condition added. So it will only loop through that if it is present. Check this.
import React, { Component } from "react";
import http from "../services/httpService";
import { postEndPoint, repliesEndPoint } from "../config.json";
class PostPage extends Component {
state = {
post: [],
replies: [],
};
async componentDidMount() {
const id = this.props.match.params.id;
const { data: post } = await http.get(postEndPoint + "/" + id);
const { data: replies } = await http.get(repliesEndPoint + "/" + id);
console.log(post.tags, typeof post.tags);
this.setState({ post: post, replies: replies });
}
render() {
const { post, replies } = this.state;
return (
<React.Fragment>
<div className="container col-lg-8 shadow-lg p-3 mt-5 bg-body rounded">
<h2>{post.title}</h2>
<p className="mt-4" style={{ color: "#505050" }}>
{post.description}
</p>
<div className="mt-1">
Related Topics:
{post.tags && post.tags.map((tag) => ( // <--- map will only execute when it finds tags.
<span className="badge badge-secondary m-1 p-2">
{(tag).name}
</span>
))}
<h6 className="mt-2">
{(post.upvotes && post.upvotes.length) || 0} Likes {post.views} Views // <---- These default values too will handle the case where the data isnt ready yet
</h6>
<div class="d-flex w-100 justify-content-between">
<small class="mb-1">Posted by {post.author['name']}</small>
</div>
</div>
</div>
</React.Fragment>
);
}
}
export default PostPage;
Apologies if this question has been asked before and solved, but I have been searching and haven't had much luck.
I have created an app where a person can search for a book and the results are returned. The problem I am having is when I enter a book title and select the search button an empty array is rendered and then an array with the proper results are returned but not rendered. When I select the search button again the proper results are rendered. I would like the correct results to be rendered on the first click.
I logged the results and it looks like the empty array is being rendered first instead of the correct results. I believe it could be due to the async nature of the API call.
Here is my code:
class App extends Component {
state = {
data: []
}
handleBookSearch = (book) => {
let data = utils.searchBooks(book);
this.setState({ data: data });
}
render() {
return (
<div className="">
<Banner
onSearch={this.handleBookSearch}
onRender={this.renderBooks} />
<div className="custom-margin">
<BookDisplay bookData={this.state.data} />
</div>
</div>
);
}
}
export default App;
class PostDisplay extends Component {
render() {
const { bookData } = this.props;
return (
bookData.map(book => (
<div>
<div className="cap-color">
<h4 className="card-header"><i className="fas fa-book fa-fw"></i>{book.title}</h4>
</div>
<div className="card-body">
<img src={book.thumbnail} alt={book.title} />
<h5 className="card-title margin-above"><b>Author:</b> {book.authors}</h5>
<h6><b>Publisher:</b> {book.publisher}</h6>
<h6><b>Published On:</b> {book.publishedDate}</h6>
<h6><b>Supported Languages:</b> {book.language}</h6>
<p className="card-text"><b>Description:</b> {book.description}</p>
<a href={book.link} target="_blank" rel="noopener noreferrer"
className="btn btn-primary cap-theme-project">Buy the book!</a>
</div>
</div>
))
);
}
}
export default PostDisplay;
class Banner extends Component {
constructor() {
super();
this.state = {
search: ''
};
}
updateSearch(event) {
const searchParam = event.target.value;
this.setState({ search: searchParam });
}
render() {
return (
< div className="title-banner" >
<h1 className="header-padding"><i className="fas fa-book fa-fw"></i><b>Google Library</b></h1>
<div className="container">
<div className="row justify-content-center">
<div className="col-12 col-md-10 col-lg-8 opacity">
<div className="card-body row no-gutters align-items-center">
<div className="col">
<input className="form-control form-control-lg form-control-borderless"
type="text" placeholder="Search for a book..." ref="searchQuery"
value={this.state.search}
onChange={this.updateSearch.bind(this)} />
</div>
<div className="col-auto">
<button onClick={() => this.props.onSearch(this.state.search)}
className="btn-margin btn btn-lg btn-primary"><i class="fas fa-search"></i></button>
</div>
</div>
</div>
</div>
</div>
</div >
);
}
}
export default Banner;
var books = require('google-books-search');
export let data = [];
export function searchBooks(title) {
books.search(title, function (err, results) {
if (!err) {
data = results;
} else {
console.log('ERROR: ' + err);
}
});
return data;
}
Use callback function. It will set state after callback method called.
handleBookSearch = (book) => {
let data = utils.searchBooks(book,(data)=>{
this.setState({ data: data });
});
}
export function searchBooks(title,callback) {
books.search(title, function (err, results) {
if (!err) {
callback(results);
} else {
console.log('ERROR: ' + err);
}
});
}
Yes your assumption is correct it is due to async operation. Handle promise like this.
handleBookSearch = async (book) => {
let data = await utils.searchBooks(book);
this.setState({ data: data });
}