Home > Software design >  I am changing the state of the REACT component from another component but no refresh
I am changing the state of the REACT component from another component but no refresh

Time:02-11

I need a light to see what is missing?. I am changing the state of the Users REACT component when I add a user to the backend. The user added with no issues. And I send the state of the User element in and I change the state when "onSubmit:" happened but the Users REACT component didn't reload . What is wrong with this approach?

import { v4 as uuidv4 } from 'uuid';
import React, { useState, useEffect }  from 'react';
import { useFormik } from 'formik';
function unique_id() {
    return uuidv4()
}
var PlayersBackend='/players';
const validate = values => {
    const errors = {};
    if (values.firstName === 0 || values.firstName.replace(/^\s |\s $/gm, '').length === 0) {
        errors.firstName = 'Required';
    } else if (values.firstName.length === 0) {
        errors.firstName = 'The message must be no empty';
    }

    if (values.lastName === 0 || values.lastName.replace(/^\s |\s $/gm, '').length === 0) {
        errors.lastName = 'Required';
    } else if (values.lastName.length === 0) {

        errors.lastName = 'The message must be no empty';
    }
    return errors;
};
const addPlayer = async (firstName, lastName) => {
    await fetch(PlayersBackend, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        credentials: 'same-origin',
        headers: {
            "Content-Type":"application/json",
        },
        body: JSON.stringify({ firstName, lastName })
    })

};


const AddPlayerForm=(compUsersState) =>{
    const formik = useFormik(
        {initialValues:{firstName: '',lastName: '',},
            validate,
            onSubmit: (values,{resetForm}) =>
        {  addPlayer(values.firstName,values.lastName).then();
            resetForm();
            console.log(compUsersState.compUsersState)
            compUsersState.compUsersState(p => p 1);

        },
    });
    return (
        <form onSubmit={formik.handleSubmit}>
            <label htmlFor="firstName">First Name</label>
            <input
                id="firstName"
                name="firstName"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.firstName}
            />
            <label htmlFor="lastName">Last Name</label>
            <input
                id="lastName"
                name="lastName"
                type="text"
                onChange={formik.handleChange}
                value={formik.values.lastName}
            />

            <button type="submit">Add user</button>
        </form>
    );
};

export const Users = () => {

    const [error, setError] = useState(null);
    const [isLoaded, setIsLoaded] = useState(false);
    const [users, setPlayers] = useState([]);
    const [,compUsersState] = useState(0);
    useEffect(() => {
        fetch(PlayersBackend).then(response => response.json()).then((data) => { setIsLoaded(true);setPlayers(data);}, (error) => {setIsLoaded(true);setError(error);})},[])
    if (error) {
        return <div>Error: {error.message}</div>;
    } else if (!isLoaded) {
        return <div>Loading...</div>;
    } else {

        if (typeof (users._embedded) !== 'undefined')
        {
            return (

                <ul>
                    <AddPlayerForm compUsersState={compUsersState}/>
                    {users._embedded.players.map(player => (
                        <li className="d-flex justify-content-start" key={unique_id()}>
                            {player.firstName} {player.lastName}
                        </li>
                    ))}

                </ul>
            );

        }
        else return  (<ul> </ul> )

    }

}

CodePudding user response:

It might be due to useEffect it only executes once when the component is loaded adding users to useEffect dependency might help

 useEffect(() => {
    fetch(PlayersBackend)
      .then((response) => response.json())
      .then(
        (data) => {
          setIsLoaded(true);
          setPlayers(data);
        },
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, [users,users.length]);

CodePudding user response:

Update: After seeing the answer about useEffect, which hints me a new idea to achieve the refreshing.

In Users,

const [refreshCounter, compUsersState] = useState(0);


useEffect(() => {
    fetch(PlayersBackend)
      .then((response) => response.json())
      .then(
        (data) => {
          setIsLoaded(true);
          setPlayers(data);
        },
        (error) => {
          setIsLoaded(true);
          setError(error);
        }
      );
  }, [refreshCounter]);

By adding the counter state into the dependency array, you can be sure that the useEffect is triggered every time the counter gets incremented.


I recommend passing setPlayers function to <AddPlayerForm>, and trigger the function to add a new player to the users list, after successfully added a player.

In Users,

<AddPlayerForm compUsersState={compUsersState} setPlayers={setPlayers} />

In AddPlayerForm,

const AddPlayerForm = ({compUsersState, setPlayers}) => {
  const formik = useFormik({
    initialValues: { firstName: "", lastName: "" },
    validate,
    onSubmit: (values, { resetForm }) => {
      addPlayer(values.firstName, values.lastName).then();
      resetForm();
      console.log(compUsersState.compUsersState);
      compUsersState.compUsersState((p) => p   1);
      const newPlayer = values; // Or change the format
      setPlayers((p) => [...p, newPlayer])
    },
  });
  ...

I can see you are trying to refresh the Users component by calling compUsersState((p) => p 1), and I think it is working. If you are not sure, inspect the element with React Developer Tool and check the state has been successfully changed.

But the actual problem is that the users state didn't get updated. So the UI looks the same as before.

CodePudding user response:

Try with forceupdate like

const forceUpdate = React.useReducer(bool => !bool)[1];

And call with state update

forceUpdate();
  • Related