I've finally figured out how to get data from the API :) but now I am stuck because I am trying to change the URL of a fetch request.
I can't figure out how to use my input in the URL as it brings up an error saying input not defined. Which I am assuming is because technically it is not linked. Am I overlooking something really simple?
Also a little background; I am trying to build a simple dictionary web application where you type in a word and it retrieves definitions. I am currently using the WordAPI API for my project.
import React from "react";
import "./App.css";
import ZipForm from "./ZipForm.js";
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: null,
isLoaded: false,
input: "",
};
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onFormSubmit(input) {
this.setState({ input });
}
componentDidMount() {
const url = `https://wordsapiv1.p.rapidapi.com/words/${input}/definitions`
fetch(url, {
method: "GET",
headers: {
"x-rapidapi-host": "wordsapiv1.p.rapidapi.com",
"x-rapidapi-key": "58143f60a0msh9b238a4cf58ba29p1e28e0jsn9e523b0104ba",
},
})
.then((response) => response.json())
.then((json) => {
this.setState({
items: json,
isLoaded: true,
});
console.log(json.definitions[0].definition);
});
}
render() {
var { isLoaded, items } = this.state;
if (!isLoaded) {
return <div>Loading...</div>;
} else {
}
return (
<div>
<h1 className="tc">{items.definitions[0].definition}</h1>
<ZipForm onSubmit={this.onFormSubmit} />
</div>
);
}
}
I believe URL should be
`https://wordsapiv1.p.rapidapi.com/words/${this.state.input}/definitions`
Related
What I want is, when I get no data from the api, instead of this No data, I want A notification or toast.error to get displayed.
shops.jsx
import React from 'react';
import './shops.css';
import Shop from './shop'
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
require('dotenv').config()
const TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI1ZjFiMjNlYTQxNmJhMjQ3YjQ5MDk4Y2IiLCJlbWFpbCI6Img1aW1icjQ0NGQ7QHR5cC5pbiIsImlhdCI6MTU5NjgxMTU5MSwiZXhwIjoxNTk2ODE1MTkxfQ.UyrUkbNWzenf50FL8AZE1iZaii11P7MwdXpKmoCB9nM";
class Shops extends React.Component {
constructor(props) {
super(props);
this.state = {
shops: []
};
}
componentDidMount() {
console.log(process.env.REACT_APP_BaseURL);
// replace with correct URL: http://localhost:5000/api/shops/allShops
fetch(process.env.REACT_APP_BaseURL, {
method: "get",
headers: new Headers({
Authorization: `Bearer ${TOKEN}`
})
})
.then(response =>response.json())
.then(data => {
this.setState({ shops: data.fetchedShops });
toast.success("API LOADED SUCCESSFULLY","SUCCESS");
})
.catch(err =>{
console.log("Error", err);
if(err){
toast.error("error occured");
}
});
}
render() {
const shops =
this.state.shops.length > 0 ?
this.state.shops.map(item => (
<Shop name={item.shopname} address={item.address} mobile={item.phoneNumber} />
))
: <span >No data</span>;
console.log(this.state.shops);
return <div id="container">{shops}</div>;
}
}
export default Shops;
In the 6th line you can see <span >No data</span> instead of this I want a toast.error notification, but when I write toast.error("No data"); instead of this span i got something like this instead of error notification
If you want to toast that there is no data when the array is empty it needs to be done in two steps since render is a pure function, i.e. without side effects
Issue toast side-effect in component lifecycle functions, i.e. componentDidMount and/or componentDidUpdate
Render null when toasting no data, or since the map can handle empty arrays without issue, just return the empty map result array
Code
class Shops extends Component {
state = {
shops: []
};
checkShops = () => {
const { shops } = this.state;
if (!shops.length) {
toast.error("No Data");
}
};
componentDidMount() {
this.checkShops(); // not really needed if fetch for data first
}
componentDidUpdate() {
this.checkShops();
}
render() {
const { shops } = this.state;
return (
<div id="container">
{shops.map((item) => <div>Data</div>)}
</div>
);
}
}
here I have an ajax request that gets the photo of a random cat
import React, { Component } from 'react';
class RandomCat extends React.Component {
constructor(props) {
super(props)
this.state = {}
this.fetchRandomCatImg = this.fetchRandomCatImg.bind(this)
}
componentDidMount() {
this.fetchRandomCatImg()
}
fetchRandomCatImg() {
fetch("https://aws.random.cat/meow")
.then(response => response.json())
.then(data => {
this.setState({
error: null,
ready: true,
src: data.file
})
})
.catch(error => this.setState({ error }))
}
render() {
if (this.state.error) return <p>Oops, something went wrong!</p>
if (!this.state.ready) return <p>Loading...</p>
return <img src={this.state.src} className="cat" alt="random cat photo" />
}
}
export default RandomCat;
here we need to make a qr image code that links to the same photo that gets generated from that call
it means we need to pass data resulted from the cat api to the other ajax call that gets the qr code
I tried doing this but it gave another photo(new one)
import React, { Component } from 'react';
class QR extends React.Component {
constructor(props) {
super(props)
this.state = {}
this.fetchQR = this.fetchQR.bind(this)
}
componentDidMount() {
this.fetchQR()
}
fetchQR() {
fetch("https://qrtag.net/api/qr_12.svg?url=https://aws.random.cat/meow" )
.then(response => response.json())
.then(data => {
this.setState({
error: null,
ready: true,
src: data.file
})
})
.catch(error => this.setState({ error }))
}
render() {
if (this.state.error) return <p>Oops, something went wrong!</p>
if (!this.state.ready) return <p>Loading...</p>
return <img className="QR"src={this.state.src} alt="qrtag"/>
}
}
export default QR;
This is a bit different but you can use this package:
https://www.npmjs.com/package/qrcode.react
And then you only need to do one API call. Once the URL of the file is in your state, you display the QR Code like this:
<QRCode value={this.state.src} />
But if you still want to use the QR code generator API, you need to pass the URL of the cat you just fetched to this component, the value of data.fetch (this.state.src).
If you pass it https://aws.random.cat/meow of course it won't work.
Using axios, I am calling to an Mongo REST API. However, whenever I press the button which I have tied to it, I get this error:
TypeError: Object(...)(...) is undefined
onSearchButtonPressed
D:/foo/hello-world/src/RecipeBuilder.js:146
> 146 | search_elastic(this.state.searchText).then({
| ^ 147 |
148 | })
149 |
Why is this happening? If I call search_elastic without appending then, it seems to work, however no data is returned. Even more interesting, if I remove encapsulation of the search_elastic method and directly insert the axios.get code block into the onSearchButtonPressed() method, there is no issue.
My class is set up like so:
import React, { Component } from 'react'
import {search_elastic, shell} from './Backend.js'
class RecipeBuilder extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
term: '',
editDisabled: false,
ingredients: [],
candidates: [],
searchText: '',
searchResults: []
}
this.onSearchTextChange = this.onSearchTextChange.bind(this)
this.onSearchButtonPressed = this.onSearchButtonPressed.bind(this)
}
onSearchTextChange(filterText) {
console.log({filterText})
this.setState({
searchText: filterText
});
}
onSearchButtonPressed() {
search_elastic(this.state.searchText).then(data => {
//ideally would like to add data from this method to the RecipeBuilder state
})
}
render () {
return (
<div className="col-md-12">
<SearchBar
searchText={this.state.searchText}
onSearchTextChange={this.onSearchTextChange}
/>
<button onClick={this.onSearchButtonPressed}>Search</button>
</div>
)
}
}
export default RecipeBuilder
The SearchBar component is set up as such:
class SearchBar extends Component {
constructor(props) {
super(props);
this.handleSearchTextChange = this.handleSearchTextChange.bind(this);
}
handleSearchTextChange(e) {
this.props.onSearchTextChange(e.target.value);
}
render() {
return (
<div>
<form>
<input
type="text"
placeholder="Search..."
value={this.props.searchText}
onChange={this.handleSearchTextChange}
/>
</form>
</div>
);
}
}
And the Backend.js can be seen here:
import axios from 'axios'
export const search_elastic = term => {
axios
.get(`api/search/${term}`, {
headers: { 'Content-type': 'application/json' }
})
.then((response) => {
console.log(response)
return response
})
}
export const shell = () => {
console.log("In shell")
}
Working revision of onSearchButtonPressed() (however I have no clue why):
onSearchButtonPressed() {
axios.get(`api/search/${this.state.searchText}`, {
headers: { 'Content-type': 'application/json' }
}).then((response) => {
//console.log(response)
if (response != null) {
var data = response["data"]
var result = data["result"]
var hitsObj = result["hits"]
var hitsArray = hitsObj["hits"]
this.setState({searchResults: [...hitsArray]})
console.log(this.state.searchResults)
}
return response
})
}
Your search_elastic function doesn't return anything. It needs to return the promise from axios.get().
// either *return* axios.get or remove the curlies for an implicit arrow function return
export const search_elastic = term => {
return axios
.get(`api/search/${term}`, {
headers: { 'Content-type': 'application/json' }
})
.then((response) => {
console.log(response)
return response
})
}
I am new to the react and I am learning how to HTTP get request using axios. I am referring to a youtube video: https://www.youtube.com/watch?v=NEYrSUM4Umw and following along, but I got an error. I think I have minor error but I can't figure it out.
import React, { Component } from 'react'
import axios from 'axios'
class PostList extends Component {
constructor(props) {
super(props)
this.state = {
posts: []
}
}
componentDidMount(){
axios.get('https://api.particle.io/v1/devices/64646468431646/temperature?access_token=547376a1b2')
.then(response => {
console.log(response)
this.setState({posts: response.data})
})
.catch(error => {
console.log(error)
}
)
}
render() {
const { posts } = this.state
return (
<div>
temperature
{
posts.length ?
posts.map(post => <div key={post.coreInfo.deviceID}> {post.result} </div>) :
null
}
</div>
)
}
}
export default PostList
When I use postman to get a HTTP request, I get the following response:
{
"cmd": "VarReturn",
"name": "temperature",
"result": "67.55",
"coreInfo": {
"last_app": "",
"last_heard": "2020-04-05",
"connected": true,
"last_handshake_at": "2020-04-05",
"deviceID": "64646468431646",
"product_id": 8
} }
My goal is to display the result: 67.55 in the web application.
Thank you in advance
If you're only getting a single object as the response from your fetch instead of an array, just wrap it in an array -
this.setState({posts: [response.data]})
I got the following method:
export const getPublication = async (id, props) => {
const idJSON = {"id": id,}
return await axios({
method: 'post',
url: 'users/getPublicationByID',
data: idJSON
})
.then(function (response) {
return response.data
})
.catch(function (error) {
alert(error.response.status); // Works fine
props.history.push({
pathname: '/error',
state: { hasError: true, coding: error.response.status }
})
});
}
Now, this method seems to work fine as it redirects me from the page I was to '/error' when an error is caught. However, the error page doesn't seem to update its coding variable.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {
hasError: false,
coding: props.coding
};
}
render(){
const { t } = this.props;
var codeMsg = t('errors.errorCode') + this.state.coding;
alert(codeMsg); // says it's undefined!
return (
...
);
}
}
export default withTranslation()(ErrorBoundary);
The state provided to routed components is available at location.state
coding: props.location.state.coding
docs