I'm trying to update state in React.js using an API call, as I need to show some of the data to the end user.
The api call works through localhost:5001 and is stored in Firebased functions.
import React, { Component } from 'react'
import './Table.css';
class Table extends Component {
constructor (props)
{
super(props);
this.state = {
stocks: []
};
}
componentDidMount() {
fetch('localhost:5001') // Removed for stackoverflow //
.then((response) => response.json())
.then(stockList => {
this.setState =
({ stocks: stockList });
});
}
render() {
return (
<div className='table'>
<h1 id='title'>Companies</h1>
{this.state.stocks.map(stocks => <h2 key={stocks.symbol}> {stocks.companyName}</h2>)}
</div>
)
}
}
export default Table;
Here is a snippet of the API call:
{"symbol":"AAPL","companyName":"Apple Inc"}
setState is a function, so you should call it, rather that assign values to it:
this.setState({ stocks: stockList });
Related
Ok so I am trying to understand React Hooks and how to update
my code to grab the JSON from the source below and show the data. I'm clear on importing the hook and initializing it with useState(0) but my code fails when I try to re-factor within my fetch statement. Any/all help would be greatly appreciated...see below.
// import React, { Component } from 'react';
import React, { useState } from 'react';
import Feeder from './Feeder';
import Error from './Error';
// class NewsFeeder extends Component {
// constructor(props) {
// super(props);
// this.state = {
// news: [],
// error: false,
// };
// }
const [hideNews,showNews] = useState(0);
componentDidMount() {
const url = `https://newsfeed.com`;
fetch(url)
.then((response) => {
return response.json();
})
.then((data) => {
this.setState({
news: data.articles
})
})
.catch((error) => {
this.setState({
error: true
})
});
}
renderItems() {
if (!this.state.error) {
return this.state.news.map((item) => (
<FeedPrime key={item.url} item={item} />
));
} else {
return <Error />
}
}
render() {
return (
<div className="row">
{this.renderItems()}
</div>
);
}
}
export default NewsFeeder;
React hooks are created for functional components and are not ment to be used in class components.
Here is a table of the functionality and the way to achive it using classes and functions with hooks.
component type
state
fetch
class
store the state in this.state that you only assign once in the constructor, use this.setState to modify the state
do your fetch logic in componentDidMount
function
create a pair of [example, setExample] with useState
do fetch in useEffect hook
Using fetch with hooks: (edited version of this):
import React, { useState, useEffect } from 'react';
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(async () => {
const result = await fetch('https://hn.algolia.com/api/v1/search?query=redux').then(response => response.json());
setData(result);
});
let items = data.hits.map(item => (
<li key={item.objectID}>
<a href={item.url}>{item.title}</a>
</li>
));
return (
<ul>
{items}
</ul>
);
}
export default App;
Hi I am working on a react app with Routing and HOC. I expect to see a page but i get page not found when i know the page is there.
in componentDidMount this.setState, data is shown as undefined but in the HOC wrapper i see the data arrive from the server.
Before I wrapped the page in HOC i could see it rendering content so I know the content exists.
Here is my Page component which is being called via a Route :
import React, { Component } from "react";
import WithBackend from "./WithBackend";
class Page extends Component {
constructor(props) {
super(props);
this.state = { model: null };
}
render() {
if (this.state.model != null) {
return (
<div className="container">
<div className="row">
<div className="col-md">
<h1>{this.state.model.title}</h1>
</div>
</div>
</div>
);
} else {
return (
<div>
<h2>Home</h2>
</div>
);
}
}
componentDidMount() {
const data = this.props.getPage("1");
console.log(data);
this.setState({
model: data,
});
}
}
export default WithBackend(Page);
Here is the HOC component WithBackend: I am not sure if i should be setting the state on this class on in the class that is being wrapped.
When i debug the code in the getPage method, in the setState part i see the data being populated from the backend server.
import React from "react";
import ContentService from "./ContentService";
const WithBackend = (WrappedComponent) => {
class HOC extends React.Component {
constructor() {
super();
this.contentService = new ContentService();
this.getPage = this.getPage.bind(this); // <-- Add this
}
getPage(id) {
this.contentService
.getPage(id)
.then((response) => response.json())
.then((data) => {
this.setState({ model: data });
})
.catch((e) => {
console.log(e);
});
}
render() {
return <WrappedComponent getPage={this.getPage} {...this.props} />;
}
}
return HOC;
};
export default WithBackend;
and here is the contentService which only returns a promise:
class ContentService {
pageUrl = process.env.REACT_APP_BASE_URL + "/pages/";
getPage(id) {
const path = this.pageUrl + id;
const fetchPromise = fetch(path, {
method: "GET",
});
return Promise.resolve(fetchPromise);
}
}
export default ContentService;
Could anyone please advice what i am doing wrong?
Thanks in advance.
getPage is an asynchronous method, that should return a promise:
getPage(id) {
return this.contentService
.getPage(id)
.then((response) => response.json())
.catch((e) => {
console.log(e);
});
}
And then
componentDidMount() {
this.props.getPage("1").then(model => this.setState({ model }));
}
i am new in react. Can anyone help me that How to call API using react js and show the response in page. I am trying the following code but getting error.
export default class UserList extends React.Component {
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const users = res.data;
this.setState({users});
})
}
render() {
return (
<ul>
{this.state.users.map(user => <li>{user.name}</li>)}
</ul>
)
}
}
Hi you missed to declare the state. you need to declare it in UserList Component. Please follow this example:
import React from 'react';
import axios from 'axios';
export default class UserList extends React.Component {
state = {
users: []
};
componentDidMount() {
axios.get(`https://jsonplaceholder.typicode.com/users`)
.then(res => {
const users = res.data;
this.setState({users});
})
}
render() {
return (
<ul>
{this.state.users.map(user => <li>{user.name}</li>)}
</ul>
)
}
}
How can I do an ajax call each time the store gets updated?
Basically, I want to fetch products with new API params, let's say there is a drop-down for items per page. It is working fine on load, i.e on call of method componentWillMount
But I'm not sure how to do a fetch again on when the store changes.
import React, { Component } from 'react';
import ProductsList from '../components/ProductsList'
import { connect } from 'react-redux'
// Action Creators
import doFetchProducts from '../actions/doFetchProducts'
import queryString from 'query-string'
class Products extends Component {
constructor (props) {
super(props);
}
componentWillMount () {
this.fetch()
}
fetch () {
let q = queryString.stringify({
categories: 'rings',
'attributes.Style': 'Classic',
limit: this.props.applyItemsPerPage,
page: 1,
status: 'Active'
})
this.props.dispatch(
doFetchProducts(q)
)
}
render() {
return (
<section className="content">
<ProductsList {...this.props} />
</section>
);
}
}
const mapStateToProps = state => {
return {
products: state.applyFetchProducts.products,
isLoading: state.applyFetchProducts.isLoading,
itemsPerPage: state.applyItemsPerPage
}
}
export default connect(
mapStateToProps
)(Products);
Thanks in advance.
You can use Redux's store.subscribe to listen for changes.
componentWillMount() {
this.unsubscribeStore = store.subscribe(this.onStoreChange);
this.setState({
currentState: store.getState()
});
}
componentWillUnmount() {
this.unsubscribeStore();
}
onStoreChange = () => {
const newState = store.getState();
// Check the relevant part of store for changes.
// Depends on your store implementation
if (newState.reducer.prop !== this.state.currentState.reducer.prop) {
this.fetch();
}
}
this.onStoreChange will get called on each dispatch, so be careful not to create infinite loops. That is also the reason why you have to manually check for changes when the callback function is executed.
I'm trying to test rendering a list component from an JSON object called with fetch, however I suspect the render is called before the JSON is returned as I get an undefined error. Note the debug alert() gets the value, but the render has already error on undefined. How do I handle this? Is there a way to call the render function after the data has been fetched? OR could how would I get the data to render with '?' and then update when the data arrives? Note my if (!object) doesn;t work when called as an inline wrapper - why not - or more impoartanly how would I achive this? Sorry for the begginer questions - I suspect I meant to be using a data framework to bring data for react to display but I wanted to start learning with less frameworks and get the basics. Many thanks! - code is:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class ItemLister extends React.Component {
constructor(props ) {
super(props);
this.state = { items: [] };
}
componentDidMount() {
let url = "http://localhost:8888";
let iterator = fetch(url, {method: 'GET'});
iterator
.then(response => {
//console.log('sss', response)
return response.json();
})
.then(post => {
//console.log(post)
this.state.items = post;
alert(this.state.items.users[3].firstname);
});
}
output(object){
if (!object){
return '?';
}else{
return object;
}
}
render() {
return(
<div>
<div>Items:</div>
<div>{this.output(this.state.items.users[3].firstname)}</div>
</div>
);
}
}
export default ItemLister;
your render function could be something like this:
render() {
const username = (this.state.items === []) ? placeholder : this.output(this.state.items.users[3].firstname;
return(
<div>
<div>Items:</div>
<div>{username}</div>
</div>
);
}
basically, you render a placeholder component until your data arrives, since your data fetch is async and in componentDidMount, so your render will happen initially before you have data.
although you probably want to rethink how this component is constructed in general, why are you accessing specifically users[3]?
Try this code it will help you
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
class ItemLister extends Component {
constructor(props) {
super(props);
this.state = { items: [], firstname: "" };
}
componentDidMount() {
let url = "http://localhost:8888";
let iterator = fetch(url, { method: "GET" });
iterator
.then(response => {
//console.log('sss', response)
return response.json();
})
.then(post => {
//console.log(post)
this.setState({
items: post,
firstname: this.state.items.users[3].firstname
});
alert(this.state.items.users[3].firstname);
});
}
output(object) {
if (!object) {
return "?";
} else {
return object;
}
}
render() {
return (
<div>
<div>Items:</div>
<div>{this.state.firstname}</div>
</div>
);
}
}
export default ItemLister;