Search code examples
javascriptreactjssignalr

SignalR connection.start().then() doesn't work as expected


Let's say in my reactJS client, I created a signalr hubconnection like this:

function App() {
  const [connection, setConnection] = useState();

  const createConn = async (navigateFunc) => {
    const conn = new HubConnectionBuilder()
      .withUrl('https://localhost:7028/chat')
      .configureLogging(LogLevel.Information)
      .build();
    await conn.start().then(function () {
      setConnection(conn);
      if (connection == null) console.log("connection is null")
    })
      .catch(err => console.log(err))
  }

return (
    <div className="App">
      <Routes>
        <Route path='/' element={<Login createConn={createConn}/>}></Route>
      </Routes>

    </div>
  );
}

My Login.js component (I shortened it):

const Login = ({ createConn }) => {
    const handleSubmit = (e) => {
        e.preventDefault();
        createConn();
return (
            <Form onSubmit={handleSubmit} className='mt-5'>
                <Form.Group>
                    <Form.Control placeholder='Email...' type='text' className='d-flex p-2' onChange={changeHanler} />
                    <Button variant='success' type='submit' >Join</Button>
                </Form.Group>
            </Form>
        </div>
    )
}

I got "connection is null" as the result. So clearly something is wrong here. function inside then() will be called when the promise is fulfilled, so the connection must have been established and then setConnection() got called, but as you can see my state connection is null. And no exception was logged. So what is going on? Or maybe because my understanding of Promise is incorrect? If it is, can somebody please correct me?


Solution

  • Immediately after setConnection(conn) is executed, then connection is still the old value.

    The execution of setConnection(conn) doesn't change connection immediately, but merely "schedules" the update of connection for the next render. setConnection(conn) also will cause the component to be re-rendered, i.e. the function App() is executed again, but only after all other "immediate" js code has finished its execution.

    So inside the then block, connection is still the old value, and when the App() is executed the next time, const [ connection, ... is called again, which is (of course) a new and separate variable (which should have the expected value, but too late for your then block).

    So maybe your connection variable just works as expected, but only not yet inside the then block (That depends on how you use connection in the end, which is not part of the question).

    React works more "declarative" and less "imperative", i.e. you should basically never expect that "B happens after A", but understand the guarantees that React makes, and declare the dependencies between different states.