我是一个很新的反应者,当用钩子设置状态时遇到了一些奇怪的事情。
鉴于状态配置如下:
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>
);
}