当设置数组不保持旧状态时反应钩住useState

时间:2020-07-30 07:19:29

标签: reactjs react-hooks

我是一个很新的反应者,当用钩子设置状态时遇到了一些奇怪的事情。

鉴于状态配置如下:

const [games, setGames] = useState<Array<Game>>([]);

我这样更新它:

    const addGame = (gameId: string) => {
        setGames([...games, new Game(gameId)])
    }

第二次调用addGame之后,我希望console.log(games.length)返回两个值。

不是这种情况,仅返回最新值。 我进行了一些挖掘,发现人们正在使用lambda来实现此目的,并且它确实起作用。

    const addGame = (gameId: string) => {
        setGames(games => [...games, new Game(gameId)])
    }

但是为什么呢?有人可以解释一下,谢谢。

由HMR编辑以发表评论

这是我对您的代码进行的调整(请参见注释)

import React, { useState, useEffect, useCallback } from 'react';
import SetName from './SetName';
import { useCookies } from 'react-cookie';
import * as signalR from '@microsoft/signalr';
import { Game } from '../game/domain';
import { Card, Button, Row, Col } from 'antd';

export default function Lobby() {
  const [cookie] = useCookies(['swarm']);
  const [name, setName] = useState('');
  const [games, setGames] = useState([]);
  const [hubConnection, setHubConnection] = useState();
  //add swarmName variable
  const swarmName = cookie.swarm?.name;
  useEffect(() => {
    if (swarmName) setName(swarmName);
  }, [swarmName]); //depends on swarmName
  //moved addGame here so it can be a dependency of the effect
  //  if you don't put this in a useCallback the linter will warn you
  const addGame = useCallback((gameId) => {
    setGames((games) => [...games, new Game(gameId)]);
  }, []);
  useEffect(() => {
    //defined handler here so you can remove the listener
    //  in the effect cleanup function
    const handler = (gameId) => addGame(gameId);
    const createHubConnection = async () => {
      const hubConnect = new signalR.HubConnectionBuilder()
        .withUrl('/gamehub')
        .build();
      try {
        await hubConnect.start();
        console.log('Connection successful!');
      } catch (err) {
        alert(err);
        //rethrow the error for the effect cleanup
        return Promise.reject(err);
      }
      setHubConnection(hubConnect);

      await hubConnect.invoke('JoinLobby');

      hubConnect.on('addGame', handler);
      //returning hubConnect
      return hubConnect;
    };
    //using the return value (is a promise)
    const hubConnect = createHubConnection();
    //you forgot to return a function here that removes the listener
    return () =>
      //https://docs.microsoft.com/en-us/javascript/api/@aspnet/signalr/hubconnection?view=signalr-js-latest#off
      hubConnect.then((hubConnect) => hubConnect.off('addGame', handler));
  }, [addGame]); //when addGame is a useCallback the linter detects missing dependency

  let gameRows = games.map((game, index) => (
    <div key={index}>
      {game.id}
      <hr />
    </div>
  ));

  return (
    <Row>
      <Col className="gutter-row" flex="auto"></Col>
      <Col className="gutter-row">
        <SetName name={name} setName={setName}></SetName>
        <Card title="Games" style={{ marginTop: '20px', width: '300px' }}>
          <Button
            hidden={!cookie.swarm.name}
            style={{ marginTop: '7px' }}
            type="primary"
            onClick={() => hubConnection.invoke('CreateGame')}
            block
          >
            Create Game
          </Button>
          {gameRows}
        </Card>
      </Col>
      <Col className="gutter-row" flex="auto"></Col>
    </Row>
  );
}

0 个答案:

没有答案