fkhadra / react-toastify

React notification made easy 🚀 !
https://fkhadra.github.io/react-toastify/introduction
MIT License
12.58k stars 692 forks source link

QUESTION: toast after post request #526

Closed MrGrashopper closed 4 years ago

MrGrashopper commented 4 years ago

Hey guys,

I wanna call a toast after a POST request in ".then" method but it doesn't work. On a GET request it works fine:

toast.configure() const notify = (message) => toast(message);

handleFilter() { setAxiosHeaders() axios .get('/api/v1/desks/', { params: { date: this.state.resDate, }, }) .then(response => { this.setState({ desks: response.data }); },notify("aktualisiert!")) }

But when I do this it doesnt work and I don't know why. There are no errors but I don't see the notify toast:

createReservation(id){ setAxiosHeaders() axios .post('/api/v1/desks', { reservation: { date: this.state.resDate, desk_id: id } }) .then(() => { this.setState({ resDate: new Date() }), notify("aktualisiert!"); }) };

MoltenCoffee commented 4 years ago

The way you display your code makes it hard to read, posting code in code blocks would help a lot!

I assume your code is supposed to be:

function handleFilter() {
  setAxiosHeaders();
  axios.get('/api/v1/desks/', { params: { date: this.state.resDate, }, })
  .then(response => { this.setState({ desks: response.data }); }, notify("aktualisiert!"));
}

function createReservation(id){
  setAxiosHeaders();
  axios.post('/api/v1/desks', { reservation: { date: this.state.resDate, desk_id: id } })
  .then(() => { this.setState({ resDate: new Date() }), notify("aktualisiert!"); });
}

One thing I notice, is that the get request has:

.then( (data) => { setState(data) }, notify() )

Whereas the post:

.then( () => { setState(), notify() } )

In the get example, notify() is the second parameter passed into then() and will execute when the request fails. Is this your intened functionality? Aktualisiert doesn't sound like a negative thing..

In the post example, notify() is seperated by a comma within the anonymous function in then() which I doubt is your intention. Commas do weird things.

My guess is you want to do one of these:

What would be the correct behaviour?

MrGrashopper commented 4 years ago

Hey @Thijs-Jan thanks for your reply. Its inside the .then method.

    handleFilter() {
        setAxiosHeaders()
        axios
            .get('/api/v1/desks/', {
                params: {
                    date:  this.state.resDate,
                },
            })
            .then(response => {
                this.setState({
                    desks: response.data
                });
            },notify("Datum aktualisiert!"))
    }

If I do the same for the post method it deosnt work but I don't know why:

    createReservation(id){
        setAxiosHeaders()
        axios
            .post('/api/v1/desks', {
                reservation: {
                    date: this.state.resDate,
                    desk_id: id
                }
            })
            .then(() => {
                this.setState({
                    resDate: new Date()
                });
            },
                notify("Datum aktualisiert!"))
    };

I get the same response with different data but same structure. Is it maybe something with post request rules?

MrGrashopper commented 4 years ago

Do someone can help me? :D

MrGrashopper commented 4 years ago

I tried this but still doesn't work:

    createReservation(id){
        setAxiosHeaders()
        axios
            .post('/api/v1/desks', {
                reservation: {
                    date: this.state.resDate,
                    desk_id: id
                }
            })
            .then(() => {
                this.setState({resDate: new Date()}), () => { notify("reserviert!") };
            })
    };
MoltenCoffee commented 4 years ago

Do your request succeed? Check the network tab in the developer tools to see if they return anything, or if they return errors from your backend.

Try adding a catch:

.catch((error)=>console.error(error));

to the chain as well. I have the feeling something goes wrong with your request, not toastify.

MrGrashopper commented 4 years ago

Do your request succeed? Check the network tab in the developer tools to see if they return anything, or if they return errors from your backend.

Try adding a catch:

.catch((error)=>console.error(error));

to the chain as well. I have the feeling something goes wrong with your request, not toastify.

No there is no error. Yes maybe there is another problem. But when I print my response, everything is ok. And the state is changing correctly too. I only get this key warnings: "react.development.js:164 Warning: Each child in a list should have a unique "key" prop."

MoltenCoffee commented 4 years ago

Try this:

.then(()=>{
  this.setState({resDate: new Date()});
  notify("reserviert!");
})

In your code, you're passing notify() as a second parameter to then(), making it only execute when the request fails. See the MDN for details.

MrGrashopper commented 4 years ago

Try this:

.then(()=>{
  this.setState({resDate: new Date()});
  notify("reserviert!");
})

In your code, you're passing notify() as a second parameter to then(), making it only execute when the request fails. See the MDN for details.

No still doesn't work. You may have another idea why it doesn't work?

    createReservation(id){
        setAxiosHeaders()
        axios
            .post('/api/v1/desks', {
                reservation: {
                    date: this.state.resDate,
                    desk_id: id
                }
            })
            .then(()=>{
                this.setState({resDate: new Date()});
                notify("reserviert!");
            })
            .catch((error)=>console.error(error));
    };
MoltenCoffee commented 4 years ago

Do your request succeed? Check the network tab in the developer tools to see if they return anything, or if they return errors from your backend. Try adding a catch:

.catch((error)=>console.error(error));

to the chain as well. I have the feeling something goes wrong with your request, not toastify.

No there is no error. Yes maybe there is another problem. But when I print my response, everything is ok. And the state is changing correctly too. I only get this key warnings: "react.development.js:164 Warning: Each child in a list should have a unique "key" prop."

Going back to this post; the key warnings are caused when rendering items from something iterable, for example rendering components in a .forEach or .map of an array. Just add an iterating prop of some sort: key = "item"+i.

If state is updated correctly and you can print the response, there are just a few options left:

MrGrashopper commented 4 years ago

Do your request succeed? Check the network tab in the developer tools to see if they return anything, or if they return errors from your backend. Try adding a catch:

.catch((error)=>console.error(error));

to the chain as well. I have the feeling something goes wrong with your request, not toastify.

No there is no error. Yes maybe there is another problem. But when I print my response, everything is ok. And the state is changing correctly too. I only get this key warnings: "react.development.js:164 Warning: Each child in a list should have a unique "key" prop."

Going back to this post; the key warnings are caused when rendering items from something iterable, for example rendering components in a .forEach or .map of an array. Just add an iterating prop of some sort: key = "item"+i.

If state is updated correctly and you can print the response, there are just a few options left:

  • toastify exports a toast() function. I assumed you wrapped this into notify(), but please double check you have something like this:
    import { ToastContainer, toast } from 'react-toastify';
    const notify = (message) => { toast(message) };
  • You don't render the <ToastContainer />
  • You did not import the CSS: import 'react-toastify/dist/ReactToastify.css';

this is how I did it:

import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

toast.configure()
const notify = (message) => toast(message);

class DeskItems extends Component {
.....
    createReservation(id){
        setAxiosHeaders()
        axios
            .post('/api/v1/desks', {
                reservation: {
                    date: this.state.resDate,
                    desk_id: id
                }
            })
            .then(()=>{
                this.setState({resDate: new Date()});
                notify("reserviert!");
            })
            .catch((error)=>console.error(error));
    };
.....
}
MoltenCoffee commented 4 years ago

If you render <ToastContainer /> somewhere in or next to <DeskItems /> I see no reason why this wouldn't work I'm afraid.

MrGrashopper commented 4 years ago

If you render <ToastContainer /> somewhere in or next to <DeskItems /> I see no reason why this wouldn't work I'm afraid.

Yes me too I really don't know why it doesn't work. thank you for the "key" hint. Now I don't get any warnings.

MrGrashopper commented 4 years ago

If you render <ToastContainer /> somewhere in or next to <DeskItems /> I see no reason why this wouldn't work I'm afraid. This is my render function. Is there maybe something wrong?

render() {
return (
<div className="margin-top-xl">
<ToastContainer />
<div className="row">
<div className="col-sm-12 margin-bottom">
<Button variant="secondary" className=""  type="submit" onClick={this.handleFilter.bind(this)}>anzeigen</Button>{' '}
<DatePicker className="btn btn-light" dateFormat="dd/MM/yyyy" selected={this.state.resDate} onChange={this.handleChangeDate} ref={this.userDateRef}/>
</div>
</div>
<div className="row container margin-bottom">
<h3>Freie Desks buchen</h3>
</div>
<div className="row">
{this.state.desks.map(desk => (
<div className="col-xl-3 col-md-6 col-sm-12" key={desk.id}>
<div className="card">
<div className="card-body">
<div className="row">
<div className="col-sm-9"><h5 className="card-title" >{desk.kind}-Desk</h5></div>
<div className="col-sm-3"><img src={MyImage} alt="..." className="thumbnail"></img></div>
</div>
<p className="card-text">Platznummer: {desk.id}</p>
<a href="#" className="btn btn-primary" onClick={() => this.createReservation(desk.id)} ref={this.reservationRef}>reservieren</a>
</div>
</div>
</div>
))}
</div>
</div>
);
}
MoltenCoffee commented 4 years ago

I'm afraid I don't see anything that would break this. I have used toastify several times, and I just imported the CSS and rendered <ToastContainer /> in the topmost file of my app, and just imported toast whenever I wanted, which worked. I believe toast.configure() creates a <ToastContainer /> dynamically, so perhaps not use them both.

I hope you figure it out!

MrGrashopper commented 4 years ago

I'm afraid I don't see anything that would break this. I have used toastify several times, and I just imported the CSS and rendered <ToastContainer /> in the topmost file of my app, and just imported toast whenever I wanted, which worked. I believe toast.configure() creates a <ToastContainer /> dynamically, so perhaps not use them both.

I hope you figure it out!

Thank you so much for your help 💯 You are right I don't need them both. Here is the complete component, maybe there is a failure:

import React, { Component } from 'react';
import MyImage from "../../../assets/images/workspace.png";
import axios from "axios";
import setAxiosHeaders from "./AxiosHeaders";
import DatePicker from "react-datepicker";
import Button from 'react-bootstrap/Button'
import "react-datepicker/dist/react-datepicker.css";
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';

const notify = (message) => toast(message);

class DeskItems extends Component {
    constructor(props) {
        super(props)
        this.state = {
            desks: [],
            resDate: new Date()
        };
        this.handleFilter = this.handleFilter.bind(this)
        this.reservationRef = React.createRef()
        this.userDateRef = React.createRef();

    }

    componentDidMount() {
        axios
            .get('/api/v1/desks/', {
                params: {
                    date:  this.state.resDate,
                },
            })
            .then(response => {
                this.setState({
                    desks: response.data
                });
            })
    }

    handleFilter() {
        setAxiosHeaders()
        axios
            .get('/api/v1/desks/', {
                params: {
                    date:  this.state.resDate,
                },
            })
            .then(response => {
                this.setState({
                    desks: response.data
                }),
                    notify("Datum aktualisiert!");
            })
    }

    handleChangeDate = date => {
        this.setState({
            resDate: date
        })
    };

    createReservation(id){
        setAxiosHeaders()
        axios
            .post('/api/v1/desks', {
                reservation: {
                    date: this.state.resDate,
                    desk_id: id
                }
            })
            .then(()=>{
                this.setState({resDate: new Date()});
                notify("reserviert!");
            })
            .catch((error)=>console.error(error));
    };

    render() {
        return (
            <div className="margin-top-xl">
                <ToastContainer />
                <div className="row">
                    <div className="col-sm-12 margin-bottom">
                        <Button variant="secondary" className=""  type="submit" onClick={this.handleFilter.bind(this)}>anzeigen</Button>{' '}
                        <DatePicker className="btn btn-light" dateFormat="dd/MM/yyyy" selected={this.state.resDate} onChange={this.handleChangeDate} ref={this.userDateRef}/>
                    </div>
                </div>
                <div className="row container margin-bottom">
                    <h3>Freie Desks buchen</h3>
                </div>
                <div className="row">
                    {this.state.desks.map(desk => (
                        <div className="col-xl-3 col-md-6 col-sm-12" key={desk.id}>
                            <div className="card">
                                <div className="card-body">
                                    <div className="row">
                                        <div className="col-sm-9"><h5 className="card-title" >{desk.kind}-Desk</h5></div>
                                        <div className="col-sm-3"><img src={MyImage} alt="..." className="thumbnail"></img></div>
                                    </div>
                                    <p className="card-text">Platznummer: {desk.id}</p>
                                    <a href="#" className="btn btn-primary" onClick={() => this.createReservation(desk.id)} ref={this.reservationRef}>reservieren</a>
                                </div>
                            </div>
                        </div>
                    ))}
                </div>
            </div>
        );
    }
}

export default DeskItems
MrGrashopper commented 4 years ago

I think it's not a JS problem. It's on my backend side

bhargavamamidi commented 2 years ago

Hii @MrGrashopper, hope you are doing fine,

I am also facing the same issue bro, have you resolved the above issue? if yes please respond with a solution. that would be really helpful.

Thank you.