I have a component that calls api and returns data, url is like this: https://myapi/CLASS_NBR. But right now the api does not get fired and it returns null. I checked the browser network status, there is not api call. Any idea? My code is as below:
import React, { Component } from "react";
import axios from "axios";
class CourseDetail2 extends Component {
state = {
CLASS_NBR: this.props.match.params.CLASS_NBR,
course: null
};
componentDidMount() {
const { CLASS_NBR } = this.state;
this.runSearch();
}
runSearch = async () => {
const response = await axios.get(
`api/${this.props.match.params.CLASS_NBR}`
);
this.setState({ course: response.data });
};
render() {
const course = this.state.course; //null here
return (
<div>
Course Detail: CLASS NBR {this.props.match.params.CLASS_NBR}
////this information is passed in through react-router Link
{course.SUBJECT} //null
CATALOGNO:{course.CATALOG_NBR}//null
</div>
);
}
}
export default CourseDetail2;
Related
I have a code which access data from GraphQL API in an arrow function:
const LinkList = () => {
const { loading, error, data } = useQuery(CURRENCIES);
if (loading) return <Loader/>;
if (error) return <pre>{error.message}</pre>
return (
<div className="options">
{data.currencies.map((currency) => {
return (
<button
key={currency}
id={currency}
className="option"
>
{currency.symbol}
{currency.label}
</button>
);
})}
</div>
);
};
But I really need to implement this piece of code with access to it in a class component. I was searching a documentation with accessing data in a classes, but nothing.
Any ideas?
You can use #apollo/client package and we can use client.query directly in the class component
import {
ApolloClient,
gql,
InMemoryCache,
NormalizedCacheObject
} from '#apollo/client';
const client = new ApolloClient<NormalizedCacheObject> ({
cache: new InMemoryCache({}),
uri: 'https://countries.trevorblades.com'
});
import * as React from 'react';
const GET_Countries = gql`
query {
countries{
code
name
}
}
`;
class App extends React.Component {
getData = async () => {
let res = await client.query({
query: GET_Countries
})
console.log(res)
// Set the state to make changes in UI
}
componentDidMount() {
this.getData()
}
render() {
return "Test";
}
}
export default App;
I have a function which calls an axios.post, this function returns the obejct to the main react App, which should then save it / show it on the screen.
The return of the "postData" function (in API) looks like this:
return axios.post(url, object).then((res) => res.data);
In the main react app, I have:
async postData (file1, file2, algorithm) {
this.setState({
anomalies: await api.postData(file1, file2, algorithm)
}, () => { console.log(this.state.anomalies); }
)
}
When I console.log the anomalies (as in code), I get undefined.
In addition, I have a div as:
<div> {this.state.anomalies} <div/>
Which shows relevant content, but after the call doesn't show anything.
If I do:
axios.post(url, object).then((res) => console.log(res.data);
I get the correct object printed. So then how can I pass this object in the correct way to the React app?
Thanks!
App.js file
import React from "react";
import API from "./API";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { anomalies: null };
}
post = async () => {
this.setState(
{
anomalies: await API.postData()
},
() => {
console.log(this.state.anomalies);
}
);
};
render() {
return (
<div>
<button onClick={this.post}> click</button>
</div>
);
}
}
API.js file
import axios from 'axios'
function postData () {
return axios.get("https://jsonplaceholder.typicode.com/todos/1").then( res => res.data)
}
export default {
postData
}
I'm trying to initiate the page according to user login status. For this purpose I tried to set initial state by a function but it's not updating view after api call completed.
Currenty I see Part 3 when codes are executed.
import React, { Component } from 'react';
import axios from 'axios';
import { API_BASE_URL } from './constants/apiConstants';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
loginStatus: this.loginUpdate(),
}
}
loginUpdate(){
let token = localStorage.getItem("TOKEN");
let tmpStatus = token!==""?true:false;
if(tmpStatus){
const payload = {
"token": token
}
axios.post(API_BASE_URL + 'loginCheck', payload)
.then((response) => {
tmpStatus=response.data.response;
return tmpStatus;
});
}else{
return tmpStatus;
}
return null;
}
render() {
return (
<>
{this.state.loginStatus===true &&
<p>Part 1</p>
}
{this.state.loginStatus===false &&
<p>Part 2</p>
}
{this.state.loginStatus===null &&
<p>Part 3</p>
}
</>
)
}
}
Problem:
You should update the state variable inside the then callback of Axios. You have an API call in loginUpdate function but the problem is that your HTML renders first and then your API response comes. Also, you missed return statement before Axios but putting that will also not resolved your issue.
Solution:
You should set your state variable inside the then callback.
import React, { Component } from 'react';
import axios from 'axios';
import { API_BASE_URL } from './constants/apiConstants';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
loginStatus: localStorage.getItem("TOKEN") !== '' ? true : false,
}
}
componentDidMount() {
this.loginUpdate();
}
loginUpdate(){
let token = localStorage.getItem("TOKEN");
let tmpStatus = token!==""?true:false;
if(tmpStatus){
const payload = {
"token": token
}
axios.post(API_BASE_URL + 'loginCheck', payload)
.then((response) => {
this.setState({ loginStatus: response.data.response });
});
}else{
return tmpStatus;
}
return null;
}
You should return axios result as well.
return axios.post(API_BASE_URL + 'loginCheck', payload)
.then((response) => {
tmpStatus=response.data.response;
return tmpStatus;
});
I was able resolve the issue with the following approach:
import React, { Component } from 'react';
import axios from 'axios';
import { API_BASE_URL } from './constants/apiConstants';
export default class App extends Component {
constructor(props) {
super(props)
this.state = {
loginStatus: null,
}
}
componentDidMount() {
this.loginUpdate();
}
loginUpdate(){
let token = localStorage.getItem("TOKEN");
let tmpStatus = token!==""?true:false;
if(tmpStatus){
const payload = {
"token": token
}
axios.post(API_BASE_URL + 'giris/kontrol', payload)
.then((response) => {
tmpStatus=response.data.response;
this.setState({loginStatus:tmpStatus});
});
}else{
this.setState({loginStatus:tmpStatus});
}
}
render() {
return (
<>
{this.state.loginStatus===true &&
<p>Part 1</p>
}
{this.state.loginStatus===false &&
<p>Part 2</p>
}
{this.state.loginStatus===null &&
<p>Part 3</p>
}
</>
)
}
}
While constructor is running, "loginStatus" state is set to the first result of your method "loginUpdate()", which is "null". When the method "loginUpdate()" is called in constructor, it starts the axios, but not wait for the answer of axios. It will be running as async. After the "null" value is set, constructor is finished its work. So, the result of axios will never be used.
For this reason, you should use this.setState() function when axios result is taken. Also, you should not use the method in constructor. Therefore, if you put the method in "componentDidMount" and use setState function after the result is taken on axios, you will get the result expected. In setState function you should set "loginStatus" with axios response.
I am newbie to reactjs and I would like to ask if it is possible to achieve this.
I have two files, I would like to pass the ID from Home.js to DataModel.js
Heres my code:
DataModel.js
const axios = require('axios');
const base_url = 'https://jsonplaceholder.typicode.com';
function getUSers(id) {
return axios.get(base_url + '/users/' + id)
}
export const getUSers = getUSers(id);
=================================
Home.js
import { getUSers } from './DataModels';
class Home extends Component {
constructor(props){
super(props);
this.state = {
records: ''
}
}
render(){
let id = 2;
getUsers(id); // -----> How to pass this ID?
return (
<div>
//Codes
</div>
);
}
}
Assuming your DataModel.js exists in the same origin src folder as your component. You can minimize your file by using some ES6 JavaScript.
import axios from "axios"
const base_url = 'https://jsonplaceholder.typicode.com';
export const getUsers = (id) => {
return axios.get(base_url + '/users' + id)
}
Then in Home.js you should call that function in componentDidMount() which is the React life-cycle method that is triggered after the component has first rendered (after first displaying the content).
import { getUsers } from './DataModels';
class Home extends Component {
constructor(props){
super(props);
this.state = {
records: ''
}
}
componentDidMount(){
let id = 2
getUsers(id)
.then((res) => {
this.setState({
records: res.data
})
})
}
render(){
return (
<div>
//Codes
</div>
);
}
}
Add your fetch in componentDidMount().
// Data Model
function getUsers(id) {
return axios.get(base_url + '/users' + id) // return a promise
}
export const getUsers; // named-export function
// Component
class Home extends Component {
...
async componentDidMount() {
let id = 2; // for sample use only
const users = await getUsers(id);
console.log(users); // verify if fetched correctly
}
...
}
Do not put any side effects in render() that can alter the state of the component. Say if you store user in state variable.
this.state = {
users: {},
}
async fetch = id => {
const users = await getUsers(id)
this.setState({ users }) // altering state.users
}
render() {
fetch(2) // BAD: should not be inside render.
// This will cause many re-renders if you alter state.users
}
I'm working on my first API with React. I am able to console log my current state after its loaded and the state for that array is set. However, running my component with a prop "FragrancesArray" which is set after loading the data from this.state.fragrances returns in not a function.
Using axios async and await.
No idea why? Can someone help?
Thanks.
My code:
// Core React
import React, { Component } from 'react';
// Axios
import axios from 'axios';
// Constants
import { FRAGRANCES_URL, BLOGS_URL, MAKE_UP_URL } from 'constants/import';
// Components
import Fragrances from 'components/Fragrances/Fragrances';
class App extends Component {
state = {
fragrances: [],
blogs: [],
makeup: []
}
getCoffee() {
return new Promise(resolve => {
setTimeout(() => resolve('☕'), 0); // it takes 1 seconds to make coffee
});
}
async showData() {
try {
// Coffee first
const coffee = await this.getCoffee();
console.log(coffee); // ☕
// Axios API's
const fragranceData = axios(FRAGRANCES_URL);
const blogData = axios(BLOGS_URL);
const makeupData = axios(MAKE_UP_URL);
// await all three promises to come back and destructure the result into their own variables
await Promise.all([fragranceData, blogData, makeupData])
.then((data) => {
this.setState({
fragrances: data[0],
blogs: data[1],
makeup: data[2]
});
const { blogs } = this.state;
console.log(blogs);
})
} catch (e) {
console.error(e); // 💩
}
}
componentDidMount() {
this.showData();
}
render() {
return (
<Fragrances FragranceArray={this.state.fragrances} AppURL={FRAGRANCES_URL} />
)
}
}
export default App;
In react, before you can set/use state, you need to declare it with getInitialState() but with ES6 class model you initialize state in a constructor.
class App extends Component {
constructor(props) {
super(props)
//- Initialize default state values
this.state = {
fragrances: [],
blogs: [],
makeup: []
}
}
//The rest of code stays the same.
render() {
return (
<Fragrances FragranceArray={this.state.fragrances} AppURL={FRAGRANCES_URL} />
)
}
}
More about React state