Home  >  Q&A  >  body text

Function to run before useEffect completes

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 is that let chatProps = useMultiChatLogic('xxxx-xx-x-xx-xxx', username, Secret); runs before useEffect completes. I tried moving it inside a .then but it gave hook errors and some other stuff but nothing worked.

P粉916760429P粉916760429183 days ago362

reply all(1)I'll reply

  • P粉983021177

    P粉9830211772024-04-02 00:44:59

    I think you are missing a basic understanding of React. Check out the tutorials on states, useEffect, and general control flow.

    useEffect is asynchronous - React executes the callback after the first render and whenever a variable captured in the dependencies array is set. Your dependencies array is empty, so this useEffect runs once during the component's lifecycle (after the first render).

    I don't know what Multi 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 
    Loading...
    ; } return ; }; const ChatsPage = ({username, secret}) => { const chatProps = useMultiChatLogic('xxxxx-xxx-xxx-xxx-xxx', username, secret); return (
    ); };

    Here, on the first render, we know that the request has not completed yet because username and secret are still the default empty strings, so we render a loading message. After rendering, useEffect runs and initiates the request.

    After a while, the response arrives and we set state for username and secret, which triggers another render. On this render, the username and secret values ​​are available in the response (I assume they are guaranteed to be non-empty strings in the response), so the loading message is not rendered. Instead, we render the ChatsPage component, which accepts props with response data.

    The extra component is necessary because hooks like useMultiChatLogic must be declared above any conditions < /a>. If this is not a hook, then the call can occur There is no need for additional components in the component function body after if.


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

    reply
    0
  • Cancelreply