React Toastify - Not getting error notification - reactjs

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>
);
}
}

Related

Axios result undefined inside render() method in React

I'm trying to do axios.get() request inside my react component:
I'm fetching this data from my mongo database and nodejs server is running on localhost:9000:
This is my code:
import React, { Component } from 'react'
import axios from 'axios';
export default class Home extends Component {
state = {
data : []
}
async componentDidMount() {
const {data} = await axios.get("http://localhost:9000/data")
this.setState({data});
console.log(this.state.data)
}
render(){
console.log(this.state.data);
return (
<div>
{this.state.data[0]['title']}
</div>
);
}
}
Problem is that {this.state.data[0]['title']} says
cannot read property 'title' of undefined
How can I correct this?
Thanks in advance
try it:
axios.get('http://localhost:9000/data')
.then(function (response) {
// handle success
this.setState({data:response.data});
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
});
and I think you must be used this like:
state = {
data : [{
_id:"",
what:"",
title:"",
__v:0
}]
}
{this.state.data[0].title}

how to link QR code to a cat photo (REACT)

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.

ReactJS - adding .then to function makes "this.state.searchText" invalid

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
})
}

How to customize a fetch url in React?

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`

TypeError: this.state.patients.map is not a function

i am new in react js,and i am learning to create a React application and I got a problem with mapping function:
Here's my request and how I am attempting to render the data:
class Patients extends Component {
constructor(props) {
super(props)
this.state = {
patients: []
}
}
componentDidMount() {
api.getPatients()
.then( patients => {
console.log( patients)
this.setState({
patients: patients
})
})
.catch(err => console.log(err))
}
render() {
return (
<div className=" Patientss">
<h2>List of Patient</h2>
{this.state.patients.map((c, i) => <li key={i}>{c.name}</li>)}
</div>
);
}
}
export default Patients;
here my api calling
import axios from 'axios';
const service = axios.create({
baseURL: process.env.NODE_ENV === 'production' ? '/api' : 'http://localhost:3000/patient',
});
const errHandler = err => {
console.error(err);
throw err;
};
export default {
service: service,
getPatients() {
return service
.get('/')
.then(res => res.data)
.catch(errHandler);
},
}
and I get the following error:
TypeError: this.state.patients.map is not a function
i've try to use slice aswell but it didnt work, anyone know whats wrong with my code?`
Based on the symptoms (heh), the patients object you get in api.getPatients() isn't an array.
console.log() it to see what it actually is.
EDIT: Based on the comments, the patients object looks like
{
count: 24,
patient: [...],
}
so the this.setState() call needs to be
this.setState({patients: patients.patient})
You can also do something like this as an conditional rendering. It will check that if this.state.patient exists then only it will go ahead and call this.state.patients.map function. It will also ensure that you don't receive any errors later on due to bad responses.
I updated your Patients Code example.
class Patients extends Component {
constructor(props) {
super(props)
this.state = {
patients: []
}
}
componentDidMount() {
api.getPatients()
.then( patients => {
console.log( patients)
this.setState({
patients: patients
})
})
.catch(err => console.log(err))
}
render() {
return (
<div className=" Patientss">
<h2>List of Patient</h2>
{ this.state.patients && this.state.patients.map((c, i) => <li key={i}>{c.name}</li>)}
</div>
);
}
}
export default Patients;
I hope it helps. Thanks!!

Resources