Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

function running before useEffect finishes

I have this code:

const ChatsPage = () => {
    let username = ""
    let secret = ""
    useEffect(() => {
        axios
            .post('http://localhost:3001/authenticate')
            .then((response) => {
                username = response.data.username
                secret = response.data.secret
            })
            .catch((error) => {
                console.log(error);
            });
    }, []);

    let chatProps = useMultiChatLogic('xxxxx-xxx-xxx-xxx-xxx', username, secret);

    return (
        <div style={{ height: '100vh' }}>
            <MultiChatSocket {...chatProps} />
            <MultiChatWindow {...chatProps} style={{ height: '100vh' }} />
        </div>
    );
}

The problem with it is that let chatProps = useMultiChatLogic('xxxx-xx-x-xx-xxx', username, secret); is running before the useEffect is finished. I have tried to move it inside the .then, where it gives a hooks error, and a few other things but nothing has worked.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

I think you’re missing a basic understanding of React. Check out a tutorial on state, useEffect and control flow in general.

useEffect is asynchronous–the callback is executed by React after the first render and whenever the variables captured in the dependency array are set. Your dependency array is empty, so this useEffect runs once in the component’s lifecycle, after the first render.

I have no idea what the Multi stuff is, but you could try something like this:

const ChatsPageLoader = () => {
  const [username, setUsername] = useState('');
  const [secret, setSecret] = useState('');

  useEffect(() => {
    axios
      .post('http://localhost:3001/authenticate')
      .then((response) => {
        setUsername(response.data.username);
        setSecret(response.data.secret);
      })
      .catch((error) => {
        console.log(error);
      });
  }, []);

  if (!username || !secret) {
    return <div>Loading...</div>;
  }

  return <ChatsPage username={username} secret={secret} />;
};

const ChatsPage = ({username, secret}) => {
  const chatProps = useMultiChatLogic('xxxxx-xxx-xxx-xxx-xxx', username, secret);

  return (
    <div style={{ height: '100vh' }}>
      <MultiChatSocket {...chatProps} />
      <MultiChatWindow {...chatProps} style={{ height: '100vh' }} />
    </div>
  );
};

Here, on the first render we know the request hasn’t finished because username and secret are still the default empty strings, so we render a loading message. After that’s rendered, the useEffect runs and kicks off the request.

After a few moments, the response arrives and we set state for username and secret, which triggers another render. This time, the username and secret values from the response are available (I assume they’re guaranteed to be nonempty strings), so the loading message isn’t rendered. Instead, we render the ChatsPage, which accepts props with the response’s data.

The extra component is necessary because hooks like useMultiChatLogic have to be declared above any conditions.


The golden rule of React is that state is immutable, so if any data changes from one render to the next, it has to be done through setState, not =.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading