how to update the state before rendering the component?

Tags: , , , ,



I have this app that adds “persons” to a “phonebook”, and the user can update the person’s phone if the person already exists. but I want to know to handle the problem of when the person was already deleted (i open two tabs and delete a phone in one tab, and I try to “update” it in the second tab)

I have a persons.js which handles all HTTP requests (I’m using axios) and a PersonNotification.js which tell the user if the phone is “added” or “updated” or “doesn’t exist anymore” and all the main functionalities are inside the App.js

here is my code

persons.js

import axios from "axios";
const URL = "http://localhost:3001/persons";

const getPersons = () => {
  return axios.get(URL).then((res) => res.data);
};

const addPerson = (person) => axios.post(URL, person);
// this is where i have the probelm (i think)
const updatePerson = (person, number, setErrMsg) => {
  axios
    .put(`${URL}/${person[0].id}`, {
      name: person[0].name,
      number,
    })
//i wanted the change the state of the App.js from this line after there is an error
    .catch((err) => setErrMsg("err"));
};

const deletePerson = (person) => axios.delete(`${URL}/${person.id}`);

export { getPersons, addPerson, deletePerson, updatePerson };

App.js

import React, { useState, useEffect } from "react";
import {
  getPersons,
  addPerson,
  deletePerson,
  updatePerson,
} from "./services/persons";
import Filter from "./components/Filter";
import Form from "./components/Form";
import Phonebook from "./components/Phonebook";
import PersonNotification from "./components/PersonNotification";
const App = () => {
  const [persons, setPersons] = useState([]);
  const [newName, setNewName] = useState("");
  const [newNumber, setNewNumber] = useState("");
  const [query, setQuery] = useState("");
  const [searchValue, setSearchValue] = useState([]);
  const [notification, setNotification] = useState("");
  const [errMsg, setErrMsg] = useState("");

  // fetching the data from json-server (i,e: db.json)
  useEffect(() => {
    getPersons().then((res) => setPersons(res));
  }, []);
  // function that fires after the submit
  const personsAdder = (e) => {
    e.preventDefault();
    const personsObject = { name: newName, number: newNumber };

    //checking if the name exists
    const nameChecker = persons.filter(
      (person) => person.name === personsObject.name
    );
    console.log(errMsg);
    if (nameChecker.length > 0) {
      const X = window.confirm(
        `${personsObject.name} already exists do you want to update the number`
      );

      if (X === true) {
        // updating the number if the user confirmed
        updatePerson(nameChecker, newNumber, setErrMsg);
        const personsCopy = persons;
        const index = personsCopy.indexOf(nameChecker[0]);
        personsCopy[index] = {
          id: personsCopy[index].id,
          name: personsCopy[index].name,
          number: newNumber,
        };

        setPersons([...personsCopy]);
        setNewName("");
        setNewNumber("");
        //the function the shows the notification for 5 seconds after the content was updated
        const notificationSetter = () => {
          let X = "";
          if (errMsg.length > 0) {
            X = `you can't update${nameChecker[0].name} because it doesn't exist anymore`;
          } else {
            X = `${nameChecker[0].name} was updated`;
          }
          setNotification(X);

          setTimeout(() => {
            setNotification("");
            setErrMsg("");
          }, 5000);
        };
        notificationSetter();
      }
    } else {
      //adding a new user if the name was not already in the phonebook
      setPersons(persons.concat(personsObject));
      addPerson(personsObject);
      setNewName("");
      setNewNumber("");
      //the function the shows the notification for 5 seconds after the content was added
      const notificationSetter = () => {
        setNotification(`${personsObject.name} was added`);
        setTimeout(() => {
          setNotification("");
        }, 5000);
      };
      notificationSetter();
    }
  };

//... there is still more down here; i don't know if i should copy paste all my code

PersonNotification.js

import React from "react";
import "./PersonNotification.css";

const PersonNotification = ({ notification, errMsg }) => {
  if (errMsg.length > 0) {
    return <h1 className="err">{notification}</h1>;
  }
  if (notification.length === 0) {
    return <></>;
  } else {
    return <h1 className="notification">{notification}</h1>;
  }
};

export default PersonNotification;

PS: this the github folder of this app. this is an exercise from fullstackopen.com so i hesitate a bit before posting my question here, but i spent more than 4 hours on this problem all i want is to figure out how to update the state of “errMsg” earlier, and i think after that everything will become easy

Answer

This part should help you enough to go further.

persons.js

const updatePerson = (person, number) => {
  const request = axios
    .put(`${URL}/${person[0].id}`, {
      name: person[0].name,
      number,
    });
  return request.then(response => response.data)
};

App.js

if (X === true) {
  const notificationSetter = (X) => {
    setNotification(X);

    setTimeout(() => {
      setNotification("");
      setErrMsg("");
    }, 5000);
  };
  // updating the number if the user confirmed
  updatePerson(nameChecker, newNumber, setErrMsg)
  .then(data => {
    notificationSetter(`${nameChecker[0].name} was updated`);
    console.log('persons :>> ', persons);
    console.log('data :>> ', data);
    
    const personsCopy = persons;
    const index = personsCopy.indexOf(nameChecker[0]);
    personsCopy[index] = {
      id: personsCopy[index].id,
      name: personsCopy[index].name,
      number: newNumber,
    };
    
    setPersons([...personsCopy]);
  })
  .catch(error => {
    notificationSetter(`you can't update ${nameChecker[0].name} because it doesn't exist anymore`);
    getPersons().then((res) => setPersons(res));
  })
  setNewName("");
  setNewNumber("");
}


Source: stackoverflow