I am trying to learn React by making a motor cycle spec search web application.
I am making two axios requests in /api/index.js, and I am getting an error saying
'429 (Too Many Requests)'.
What am I doing wrong here?
/api/index.js
import axios from "axios";
const options1 = {
method: 'GET',
url: 'https://motorcycle-specs-database.p.rapidapi.com/model/make-name/Yamaha',
headers: {
'X-RapidAPI-Host': 'motorcycle-specs-database.p.rapidapi.com',
'X-RapidAPI-Key': 'MyAPIKey'
}
};
const options2 = {
method: 'GET',
url: 'https://motorcycle-specs-database.p.rapidapi.com/make',
headers: {
'X-RapidAPI-Host': 'motorcycle-specs-database.p.rapidapi.com',
'X-RapidAPI-Key': 'MyAPIKey'
}
};
export const makeList = async()=>{
try{
const {data} = await axios.request(options2);
console.log('list of all makes is like this now', data);
return data;
}
catch(error){
}
}
export const fetchData = async ()=>{
try{
const {data} = await axios.request(options1);
return data;
}
catch(error){
}
}
and this is where I'm trying to use the data.
App.js
import logo from './logo.svg';
import './App.css';
import {fetchData, makeList} from './api/index';
import React, {Component} from 'react';
class App extends React.Component{
state = {
data:[],
makes:[],
}
async componentDidMount(){
const fetchedData = await fetchData();
const fetchedMakeList = await makeList();
this.setState({data:fetchedData, makes:fetchedMakeList});
//this.setState({makes:fetchedMakeList});
console.log('list of all makes in componentDIDMOUNT is like ', fetchedMakeList);
//why is this undefined??
}
render(){
return (
<div className="App">
<header className="App-header">
<h1>Some line-ups from YAMAHA</h1>
{partOfTheArray.map(data=>{
return <p>{data.name}</p>
})}
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Open React
</a>
</header>
</div>
);
}
}
export default App;
I am only requesting 2 requests, but I am getting this error message.
Assuming that you're trying to fetch data when component mounts, here is a better approach to do so:
// Import useState and useEffect
import React, {useState, useEffect} from 'react';
export default function SomeComponent() {
let [data, setData] = useState(null)
// use an useEffect with empty dependecy(empty [] as a dependecy) to fetch the data
// empty [] makes sure that you're fetching data only once when the component mounts
useEffect(() => {
fetchData().then(res => {
// check status for response and set data accordingly
setData(res.data)
// log the data
console.log(res.data)
})
},[])
return (
<div className="App">
</div>
);
}
You need to update your fetchData() function as well.
export const fetchData = async ()=>{
try{
const response = await axios.request(options1);
// return the whole response object instead of only the data.
// this helps in error handling in the component
return response;
}
catch(error){}
}
I hope it helps!
Related
I am trying to make a web application using Motorcycle Specs Database API from rapidAPI.
I want to export fetched data from index.js to App.js so that I can use the data in the app. But, when I try to console.log the fetched data in componentDidMount function in App.js, it is undefined. I don't know why at the moment, can you see why??
/api/index.js
import axios from "axios";
const options = {
method: 'GET',
url: 'https://motorcycle-specs-database.p.rapidapi.com/model/make-name/Yamaha',
headers: {
'X-RapidAPI-Host': 'motorcycle-specs-database.p.rapidapi.com',
'X-RapidAPI-Key': 'MYAPIKEY'
}
};
export const fetchData = async ()=>{
await axios.request(options).then(function (response) {
console.log(response.data);
return response.data;
}).catch(function (error) {
console.error(error);
});
}
App.js
import logo from './logo.svg';
import './App.css';
import {fetchData} from './api/index';
import React, {Component} from 'react';
class App extends React.Component{
state = {
data:[],
}
async componentDidMount(){
const fetchedData = await fetchData();
console.log('fetchedData is like this',fetchedData);
this.setState({data:fetchedData});
}
render(){
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
}
export default App;
Use try/catch instead of chaining then and catch to your promise:
export const fetchData = async () => {
try{
const { data } = await axios.request(...);
return data;
} catch (errors) {
console.log(errors);
}
}
I have a rails + react app (separate projects) and I've made an ActionCable websocket for sending simple messages from backend to the frontend. The websocket works, i can see everything on the frontend but I can't see the updates in real-time, only after refresh. I don't know how to implement the real time update.
Here is my code:
import PropTypes from 'prop-types'
import { Switch, Route } from 'react-router-dom'
import actionCable from 'actioncable'
import { DUMMY_QUERY } from 'Queries'
// app/javascript/packs/messages.js
import React, { useState, useEffect } from 'react'
import ReactDOM from 'react-dom'
import MessagesChannel from './channels/messages_channel'
function useForceUpdate(){
const [value, setValue] = useState(0); // integer state
return () => setValue(value => value + 1); // update the state to force render
}
function Dummy() {
const [messages, setMessages] = useState([])
const [message, setMessage] = useState('')
const [rerender, setRerender] = useState(false);
useEffect(() => {
MessagesChannel.received = (data) => {
setMessages(data.messages)
console.log(data)
}
}, [])
/*const handleSubmit = async (e) => {
e.preventDefault()
// Add the X-CSRF-TOKEN token so rails accepts the request
await fetch('http://localhost:3000/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ message }),
})
setMessage('')
}*/
return (
<div>
<ul>
{messages.map((message) => (
<li key={message.id}>{message.content}</li>
))}
</ul>
</div>
)
}
export default Dummy
Active cable also hat a frontend component. I have never used it together with react, but with pure js it looks something like that:
Import the lib (consumer.js):
import { createConsumer } from "#rails/actioncable"
export default createConsumer()
Load all channels defined in your repo (index.js):
const channels = require.context('.', true, /_channel\.js$/)
channels.keys().forEach(channels)
Define a js file for each channel (message_channel.js):
import consumer from "./consumer"
consumer.subscriptions.create("MessagesChannel", {
connected() {
// Called when the subscription is ready for use on the server
},
disconnected() {
// Called when the subscription has been terminated by the server
},
received(data) {
// Called when there's incoming data on the websocket for this channel
console.log(data)
}
});
Edit: Just found out there is also a npm package for the frontend components.
I am trying to fetch data from the backend and then render a custom component with props as the data fetched from the backend. Here's a snippet:
import { useEffect } from 'react';
import axios from 'axios';
import Card from './Card';
export default function DesignList() {
useEffect(() => {
async function populate() {
const response = await axios({
method: 'POST',
baseURL: 'http://localhost:3001',
url: '/recommend',
headers: { 'Content-Type': 'application/json' },
});
response.data.forEach(recommendation => {
document.getElementById('design-list').append(<Card
title={recommendation.title}
});
}
populate();
})
return (
<div id='design-list' />
)
}
I also tried to use React.createElement(<Card .../>), pushed it in an array and tried to render it but I got the same output as described below.
This gives an output on the screen but not as a HTML component. The output for each component is [object Object]
output
How do I render the components dynamically after fetching the props data from backend?
Use state for showing recommendations, not dom append.
import { useEffect, useState } from "react";
import axios from "axios";
import Card from "./Card";
export default function DesignList() {
const [recommendations, setRecommendations] = useState([]);
useEffect(() => {
async function populate() {
const response = await axios({
method: "POST",
baseURL: "http://localhost:3001",
url: "/recommend",
headers: { "Content-Type": "application/json" },
});
setRecommendations(response.data);
}
populate();
});
return (
<div id="design-list">
{recommendations.map((item) => (
<Card title={item.title} />
))}
</div>
);
}
Im making a project where I fetch an image of a recipe card from https://spoonacular.com and I want it displayed on my react.js app. For some reason I can't get the API data from displaying on the page when I run it. Please help Im really stuck. I keep getting the error that recipeList is undefined in Recipe.js but I thought it was defined?
This is my Home.js:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/716429/information?apiKey=${APIKey}&includeNutrition=false`;
function Home() {
const [food, setFood] = useState();
useEffect(() => {
if (food) {
axios
.get(URL)
.then(function (response) {
const recipeList = response.data;
setFood(recipeList);
})
.catch(function (error) {
console.warn(error);
});
}
}, [food]);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
this is my Recipe.js
import React from "react";
function Recipe({ recipeList }) {
return (
<div className="Recipe">
<div>{recipeList.title}</div>
<img src={recipeList.image} />
</div>
);
}
export default Recipe;
you need initializing empty
const [food, setFood] = useState({});
and in useEffect evaluate if food is empty
useEffect(() => {
const getData=()=>{
axios
.get(URL)
.then(function (response) {
const {data} = response;
setFood(data);
})
.catch(function (error) {
console.warn(error);
});
}
if(!food){ // validate if food is empthy to get data (food)
getData()
}
}, []); // here is not necesary use food, because never happen anything with that variable
The response example can be seen here.
To call that using axios:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/716429/information?apiKey=${APIKey}&includeNutrition=false`;
function Home() {
const [food, setFood] = useState({});
useEffect(() => {
// You can add any if-else statement here
// but you can also do the fetch without it
axios
.get(URL)
.then(function (response) {
setFood(response.data);
})
.catch(function (error) {
console.warn(error);
});
}, []);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
And based on the response, your Recipe.js should working properly.
I am trying to render time data from API endpoint http://worldclockapi.com/api/json/utc/now
The "currentFileTime" property is constantly changing but renders once on load.
I tried setInterval method to update state but it doesn't work. May be I am making some mistake?
This is App.js:
import React , { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props) {
super(props);
this.state = { data: []};
}
async componentDidMount(){
this.fetchData();
}
async fetchData() {
try {
const response = await fetch('http://worldclockapi.com/api/json/utc/now');
if (!response.ok) {throw Error(response.statusText);}
const json = await response.json();
this.setState({ data: json});
console.log(json);
}
catch (error) {console.log(error);}
}
render() {return (<div><h1>worldclockapi.com data (edit App.js)</h1>
<li>currentFileTime: {this.state.data.currentFileTime }</li>
</div> );
}
}
export default App;
How to render and update currentFileTime continuously in react component?
the problem is componentDidMount executed only once, after component mounted for the first time, for example if your state changes componentDidMount is not gonna execute again.
in your case i think it's better to use websockets but if u wanna keep useing this api u can use useEffect hook like below:
const [temp, setTemp] = useState(0)
useEffect(()=>{
setIterval(()=>{
setTemp((prevTemp)=>prevTemp+1)
}, 2000)
}, [])
useEffect(()=>{
fetchData()
}, [temp])
in the above code we have a temp variable and it's value update every 2 second and every time it gets updated the second useEffect run and the data will fetch and as a result the state's gonna change and element gets updated.
Try Calling fecthData recursively upon successful data retrieval like below.
And you don't need to put "async" in front of componentDidMount cause you ain't awaiting anything in the method call.
async fetchData() {
try {
const response = await fetch('http://worldclockapi.com/api/json/utc/now');
if (!response.ok) {throw Error(response.statusText);}
const json = await response.json();
this.setState({ data: json});
console.log(json);
// set the time below to how frequently you wanna update
setTimeout(() => this.fetchData(), 5000);
//
}
catch (error) {console.log(error);}
}
This is using the new hooks. This should solve the problems
import React, {useEffect, useState} from 'react';
import logo from './logo.svg';
import './App.css';
const App = () => {
const [state, setState] = useState({data: []});
useEffect(()=>{
fetchData();
}, [state]);
const fetchData = async () => {
try {
const response = await fetch('http://worldclockapi.com/api/json/utc/now');
if (!response.ok) {throw Error(response.statusText);}
const json = await response.json();
setState({ data: json});
console.log(json);
}
catch (error) {console.log(error);}
}
return (<div><h1>worldclockapi.com data (edit App.js)</h1>
<li>currentFileTime: {state.data.currentFileTime }</li>
</div> );
}
export default App;