Cannot read property 'setState' of undefined n fetch method of reactjs - reactjs

I am using google contact api for fetching the contact.
In fetch method's response I am getting all the contacts. But While setting the state using setState its giving an error of Cannot read property 'setState' of undefined. Here is my code.
I had also gone through tutorials for his but not able to find the extact issue in this.
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
constructor(props) {
super(props)
this.auth = this.auth.bind(this);
this.state = {
userarray: []
}
}
auth() {
var config = {
'client_id': 'my-client-id',
'scope': 'https://www.google.com/m8/feeds'
};
window.gapi.auth.authorize(config, function () {
alert("Dd")
// this.fetchtt(window.gapi.auth.getToken());
fetch("https://www.google.com/m8/feeds/contacts/default/thin?alt=json&access_token=" + window.gapi.auth.getToken().access_token + "&max-results=700&v=3.0", {
method: 'GET'
})
.then((result) => {
result.json().then((result) => {
// display all your data in console
console.log(result.feed);
result.feed.entry.map((entry, index) => {
console.log(entry.title.$t)
const user = [
name => entry.title.$t
]
this.setState({
userarray: "ss"
});
})
})
}
)
});
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title">Welcome to React</h1>
</header>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<button onClick={() => this.auth()}>GET CONTACTS FEED</button>
</div>
);
}
}
export default App;

window.gapi.auth.authorize(config, function () { will change the context in the callback use window.gapi.auth.authorize(config, () => { instead.
PS you don't need to nest your then -
.then(result => result.json())
.then(result => { ... })

Related

Can a single product detail page appear on the same page as the product list instead?

I'm tasked with using react to create our online store. So far I've succesfully called our products using the data from the API we're developing, and I've also been able to pass the data from the mapped product list to a single product page using a link.
Only issue now is that we'd like the single product to appear on the same page as the product list when it's clicked on by the user, perhaps as a component that appears above the product list (as opposed to linking to a separate page). For the life of me I cannot seem to find a method of doing this that doesn't result in an error or the app reading parameters as undefined. Admitedly, I am quite new to React, so it's possible I'm missing something very obvious.
This is the ProductList.js
import React, { useState, useEffect } from 'react';
import SingleProduct from './SingleProduct';
import { Link } from 'react-router-dom';
const API_URL = "http://exampleapiurl/ExampleCollection/Examplecollectionid";
const Products = () => {
const [products, setProducts] = useState([]);
useEffect(() => {
getProducts().then((products) => setProducts(products))
}, []);
const getProducts = () =>
fetch(API_URL)
.then((res) => res.json());
// OnClick Handler
const [isShown, setIsShown] = useState(false);
const handleClick = (e) => {
setIsShown(current => !current);
};
return (
<div className="GetProducts">
<h1> Fetch Products from a Collection </h1>
<div className="container">
<div className="row">
{/* 👇️ Ideally, we'd like the single product item to appear here on button click, as opposed to a separate page */}
{
isShown &&
<SingleProduct/>
}
{products.map((frame) => (
<div>
{/* 👇️ Current link to separate page for product*/}
<Link to={`/SingleProduct/${frame.frameId}`}>
{/* 👇️ Button to show single item on same page as product list.*/}
<button onClick={handleClick} value={frame.frameId} > View {frame.frameName}</button>
<div key={frame.frameId}>
<img src={`https://exampleimageurl/${frame.thumnail}`} />
<li>Frame Name: {frame.frameName}</li>
<li>Gender: {frame.gender}</li>
</div>
</Link>
</div>
))
}
</div>
</div>
</div>
)
}
export default Products;
This is the SingleProduct.js
class SingleProduct extends React.Component {
constructor(props) {
super(props)
this.state = {
isLoading: false,
item: [],
frameId: this.props.match.params.frameId
}
}
componentDidMount() {
this.setState({ isLoading: true });
fetch(`http://exampleapiurl/${this.state.frameId}`)
.then(response => response.json())
.then(json => {
this.setState({
item: json,
isLoading: false
})
})
}
render() {
const { item } = this.state;
return (
this.state.isLoading ?
(<h1>Loading {this.state.frameId}...</h1>)
:
(
<div>
<div className="col border text-center" key={item.frameId}>
<img src={`https://exampleimageurl/${item.framePic}`} />
<li>Frame Name: {item.frameName}</li>
<li>Gender: {item.gender}</li>
</div>
</div>
)
)
}
}
export default SingleProduct
App.js
import React, { Component } from 'react';
import { Route } from 'react-router';
import { Home } from './components/Home';
import { Layout } from './components/Layout';
import Products from './components/ProductList';
import SingleProduct from './components/SingleProduct';
export default class App extends Component {
static displayName = App.name;
render() {
return (
<Layout>
<Route exact path='/' component={Home} />
<Route path='/ProductList' component={Products} />
<Route path='/SingleProduct/:frameId' component={SingleProduct} />
</Layout>
);
}
}
So if I understand correctly you don't want to use route for passing the data instead of that you can then pass props to the SingleProduct component.
With props getting passed it should look
{
isShown &&
<SingleProduct frameId = {selectedFrameId}/>
}
Declare a new state variable to store the selected frameid
const [selectedFrameId, setSelectedFrameId] = useState<Number>();
Your onclick event will need adjustment, because you will need to pass the frameid in map function.
onClick={() => this.handleClick(frame.frameId)}
and then set the state via handleClick event
const handleClick = (frameId) => {
setIsShown(current => !current);
setSelectedFrameId(frameId);
};
With this in your SingleProduct component the fetch call can directly use the props(frameid)
fetch(`http://exampleapiurl/${this.props.frameId}`)
Also I would recommend to change SingleProduct to a functional component instead of class component.

React not rendering, empty props object

Trying to learn react, following a tutorial. I am having difficulty getting data from my API (mongodb using whatwg-fetch") and rendering the items. The database is running, and no errors in react. The developer tools reports "props object empty", did some research and narrowed it down to the asynchronous nature of react. Apparently, it is rendering before data comes in. However, I have implemented a promise and yet no change in result. Any help will be greatly appreciated.
I have added a promise.
// App.js file
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import Product from "../components/product/product"
import HttpService from "../services/http-service";
const http = new HttpService();
class App extends Component {
constructor(props) {
super(props);
this.state = {
products: []
}
// Bind functions
this.loadData = this.loadData.bind(this);
this.productList = this.productList.bind(this);
this.loadData()
};
loadData = () => {
let self = this;
http.getProducts().then(data => {
self.setState({products: data})
}, err => {
});
}
productList = () => {
const list = this.state.products.map((product) =>
<div className="inItems" key={product._id}>
<Product title={product.title} price={product.price} imgUrl=
{product.imgUrl} />
</div>
);
console.log(list)
return (list)
}
render() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Welcome
</p>
<div className="container App-main">
<div className="items">
<h1>List Of Products</h1>
{this.productList()}
</div>
</div>
</header>
</div>
);
}
}
export default App;
// service.js file
import "whatwg-fetch";
class HttpService {
getProducts = () => {
let promise = new Promise((resolve, reject) => {
fetch("http://localhost:7500/product-list", {mode: "no-cors",
credentials: 'include' })
.then(res => {
resolve(res.json())
}).catch(err => {
if (err) throw err;
reject(err)
})
});
return promise;
}
}
export default HttpService;
Expecting items to display on screen. Nothing displays and no errors in console.
you need to await Data (const data = await http.getProducts()) or simply use axios https://www.npmjs.com/package/axios
.then mean once you receive response, you gonna do something, still the outer scope will keep running and still data is empty

Why am I getting a blank screen while following React JS?

I am following the current tutorial:
Youtube tutorial at 12:51 mins.
I expect to see bunch of posts on my screen but my screen remains blank.
It appears I have followed everything told in the tutorial.
import React, { Component } from 'react';
class Posts extends Component {
constructor(props) {
super(props);
this.state = {
posts: []
}
}
componentWillMount() {
fetch('https://jsonplaceholder.typicode.posts')
.then(res => res.json())
.then(data => this.setState({posts: data}))
}
render() {
const postItems = this.state.posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
</div>
));
return (
<div>
<h1>Posts</h1>
{ postItems }
</div>
);
}
}
export default Posts;
and
import React, { Component } from 'react';
import './App.css';
import Posts from './components/Posts'
class App extends Component {
render() {
return (
<div className="App">
<Posts />
</div>
);
}
}
export default App;
My browser screen remains blank and I do not see any errors on console.
What am I missing ?
Don't know about the tutorial but it looks outdated...
Here is your App.js (parent component):
import React, { Component } from 'react';
import Posts from './Posts';
export default class App extends Component {
state = { posts: [] };
//fetch the posts and store them in the state
componentDidMount() {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(posts => this.setState({ posts }))
.catch(error => console.log(error));
}
render() {
return (
<div>
{/* pass the state (posts) as props to Posts */}
<Posts posts={this.state.posts} />
</div>
);
}
}
Here is your Posts.js:
import React from 'react';
// No need for a class based comp
// destructure the props and you have all your data
const Posts = ({ posts }) => (
<div>
{posts.map(post => (
<div key={post.id}>
<h3>{post.title}</h3>
<p>{post.body}</p>
<hr />
</div>
))}
</div>
);
export default Posts;
Live Demo: https://jsfiddle.net/ctszdue9/7/
Try putting side effect/ api call inside
componentDidMount() { }
Change URL
https://jsonplaceholder.typicode.posts/
TO
https://jsonplaceholder.typicode.com/posts

React API elements not displaying on page

I've been looking for about 2 hours into why I am not displaying any of the information to the page. I've console logged my response from a simple random quote api and it shows, Author: and Quote: in the console, however these are not appearing in my fields, All I am seeing is the button.
import React, { Component } from 'react';
import QuoteMachine from './Quotemachine';
const END_POINT = 'https://random-quote-
generator.herokuapp.com/api/quotes/random';
class App extends Component {
constructor(props) {
super(props);
this.state = {
quote: {
text: '',
author: ''
}
}
}
getQuote() {
fetch(END_POINT)
.then(response => response.json())
.then(response => {
this.setState = ({
quote: response
});
console.log(response);
})
}
componentDidMount() {
this.getQuote();
}
render() {
return (
<div className="App">
<div className="container">
<QuoteMachine quote= {this.state.quote} />
<button id="new-quote" className="primary-color-
background" onClick={() => this.getQuote()}>New quote</button>
</div>
</div>
);
}
}
export default App;
And then here is my Quotemachine.js
import React from 'react'
import PropTypes from 'prop-types';
const QuoteMachine = (props) => {
return (
<div className="quote-box">
<div className="text">
<span>{props.quote.text}</span>
</div>
<div className="author">
<span >{props.quote.author}</span>
</div>
</div>
);
};
QuoteMachine.propTypes = {
quote: PropTypes.object.isRequired
};
export default QuoteMachine;
It is only displaying the button, but the console.log shows
Object
author:
"Thomas Henry Huxley (1825-1895)"
quote:
"Try to learn something about everything and everything about something."
proto
:
Object
Install React Developer Tools plugin and check if your state is changing after the API call

ReactJS error TypeError: Cannot read property 'map' of undefined

I'm attempting to consume a JSON API using fetch; the error mentioned above appears on the following line: **this.state.data.map( (dynamicData,key)=>**
This is my ReactJS code with the error line in bold:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
//constructor
constructor() {
super();
this.state = {
data: [],
}
} //end constructor
componentDidMount(){
return fetch('https://jsonplaceholder.typicode.com/todos')
.then((response)=>response.json())
.then((responseJson)=>
{
this.setState({
data:responseJson.todos
})
console.log(this.state.data)
})
} // end component did mount
render() {
return (
<div>
<h2>Todo:</h2>
<div>
{
**this.state.data.map( (dynamicData,key)=>**
<div>
<span> {dynamicData.userId} </span>
<span> {dynamicData.id} </span>
</div>
)
}
</div>
</div>
);
}
}
export default App;
Could I get some help as to what I'm doing wrong? Thanks in advance
import React, { Component } from "react";
import { render } from "react-dom";
class App extends Component {
state = {
data:[],
url: "https://jsonplaceholder.typicode.com/todos"
};
componentDidMount() {
fetch(this.state.url)
.then(response => response.json())
.then(data => this.setState({ data }));
}
render() {
const { data } = this.state;
data && console.log(data);
return (
<div>
{data &&
data.map(item => <div> Hello User With Id: {item.userId} </div>)}
</div>
);
}
}
render(<App />, document.getElementById("root"));
Your didMount should look like mine also, setState takes a callback so if you wanted to see what the data looked like it would be like this
this.setState({ data }, () => console.log(this.state.data))
In your render it looks like you forgot the parenthesis after the arrow function in map.
render() {
return (
<div>
<h2>Todo:</h2>
<div>
{
this.state.data.map((dynamicData,key)=> (
<div>
<span> {dynamicData.userId} </span>
<span> {dynamicData.id} </span>
</div>
))
}
</div>
</div>
);
}

Resources