簡體   English   中英

用 useState 鈎子更新對象的 state 后做出反應,我不能調用它的任何函數

[英]React after updating an object's state with useState hook, I can't call any of its functions

我正在為上下文制作一個二十一點算牌培訓應用程序。

它目前處理卡片並具有基本的hit功能,我在處理拆分(太多嵌套數組)時遇到了復雜性,所以我想我會制作一個PlayersPlayer對象,但我在嘗試更新時遇到了問題state 與useState掛鈎。

主要問題是我顯然使用useState()鈎子錯誤地更新了對象 state。 我幼稚的假設是,如果我有我的players器 object 及其內部 state,我調用函數來更新 state,然后做一個簡單的setPlayers(players) 我在網上讀到因為它是 object,所以你必須對其進行深度復制,以便 React 將其識別為新的 object 或類似的東西。 當我執行上述想法時,我的useEffect()鈎子對players更新做出反應,從不執行 - 所以它沒有接受 object 更改。 另一方面,我的用戶界面確實更新了……這讓我很困惑。

我嘗試了許多在網上找到的不同方法(有很多關於此的帖子,但每個解決方案都給我同樣的錯誤,讓我覺得我只是不理解某些東西),但都取得了不同程度的成功。 如果我做

setPlayers({...players})

我的useEffect鈎子的執行方式與setPlayers(player)不同。 問題在於這樣做,在調用setPlayers({..players})之后,我在處理后嘗試第二次擊中時收到以下錯誤。 我可以處理,然后點擊一次,然后我得到以下信息: Uncaught TypeError: players.hit is not a function 我使用回調找到了其他解決方案,但我得到了同樣的錯誤。

我做了一個PlayersPlayer class(不是組件)來處理一些手部邏輯。 我遇到了處理拆分二十一點手的復雜性,所以我想我會將其抽象為 class。 我很確定將這些類與useState()一起使用會讓我遇到問題。 我查看了有關更新 object 以便重新渲染的其他帖子,它們會產生不同的行為,但我真的不想要...

所以我的PlayersPlayer class 是非常有狀態的,許多函數不返回值,他們只是更新他們的內部hands state。

這是我的PlayersPlayer class。

class Players {
    constructor(numPlayers) {
        this.numPlayers = numPlayers;
        this.players = new Array(numPlayers).fill().map( () => (new Player()));
        this.currentPlayer = 0;
    }
    hit(card) {
        this.players[this.currentPlayer].hit(card);
    }
}

class Player {
    constructor() {
        this.hands = [[]];
        this.currentHand = 0; // for splits
        this.numHands = 1;
        this.double = false;
    }
    getCurrentHand() {
        return this.hands[this.currentHand];
    }

    hit(card) {
        this.getCurrentHand().push(card);
        return this.hands;
      }
    //other functions like split() here, omitting for clarity.

這是我的應用程序啟動的地方。 我讓我的playerssetPlayers 所有這些都按預期工作,它初始化了它需要的 state,當一切准備就緒時,它會分發卡片。 我在屏幕上看到了我想要的卡片。 我將把我的Hands組件放在最后,所以這不是所有的浮動代碼,但它與我不認為的問題無關。

export default function App() {

  const [deck, setDeck] = useState(initDeck());
  const [count, setCount] = useState(0);
  const [players, setPlayers] = useState(new Players(numPlayers));

  useEffect(() => {
    deal(deck, count, setCount, players, setPlayers);
  }, []);

  useEffect(() => {
    console.log(players);
  }, [players])
}

這就是我的問題所在:我經歷了很多不同的方式,在 App 中,如何使用setPlayers() 我不會發布我所有的嘗試,但所有結果要么是useEffect鈎子沒有在更改時執行,要么當我之前使用它時說某事不是 function。 它以某種方式錯誤地復制了 object 並失去了調用任何 function 的能力......

這是我在應用程序中的hit function,我正在處理我的const [players, setPlayers] = useState(new Players(numPlayers)); 我一開始就創造了。

我沒有遇到setCount的任何問題,因為它只是一個簡單的 integer。

function hit(deck, count, setCount, players, setPlayers) {
  let card = deck.pop();
  setCount(incrementCardCount(card, count));
  players.hit(card);
  setPlayers({...players}); // this updates with the useEffect([players]). Others don't. 
}

我也嘗試過奇怪的東西,比如在 function 開頭的let newPlayers = players player ,然后嘗試setPlayers(newPlayers) ,但這些奇怪的解決方案都沒有我試圖解決手頭的問題。 感覺就像我完全錯過了 React 的基本內容,或者對象或其他東西上的useEffectuseState

Hands組件只是放在這里,與問題無關。 它循環播放我的Players並在我想要的屏幕上顯示他們的牌。

return (
<View key={styles.playerHands}>
    {props.players.players.map((player, i) =>
        <View key={`player-${i}`} style={styles.player}>
            {player.hands.map((cards, j) =>
                <View key={`player-${i}-${j}`} style={styles.hand}>
                    {cards.map((card, k) =>
                        <Image key={`player-${i}-${j}-${k}`} style={createCardOverlap(k, j)} resizeMode={'contain'} source={displayCard(card)} />
                    )}
                </View>
            )}
        </View>
    )}
</View>
)

希望這已經得到了充分的解釋,重申我正在嘗試了解如何在我的Players obj 上使用setPlayers() 我很困惑如何做到這一點setPlayers({...players}); 完全剝奪了它調用任何函數的能力,並且在我調用player上的一些函數以更新其 state 之后,我不知道如何解決明顯的setPlayers(players)問題。

我這樣做是否正確,因為感覺就像我錯過了一些東西。 所有更新 state 都發生在 App 中,我的Players obj 只是正常更新其內部 state。

謝謝

setPlayers({...players}); 創建一個新的普通 object 並用players自己的公共數據屬性填充它。 不會創建Players實例; 普通的 object 沒有正確的原型,也沒有被Player構造函數初始化。 為此,您需要調用new Players

我發現我很少使用 state 中的對象,這些對象不僅僅是普通對象(傳播適用),但有時它很方便。 如果要使用Players ,則需要更新Players以提供一種通過必要的更改創建新Players object 的方法。

FWIW,我不會有Players class,它似乎沒有提供太多東西。 我只需要一個Players數組並將currentPlayer保存在 state 中。 然后讓Player.prototype.hit返回一個新的、更新的Player object。 Since objects in state must not be directly modified , you'd probably want to write Player using immutable methodology (methods don't modify the state of the object, they return a new object with the updated state).


附帶說明一下,“ 不要直接修改 state ”規則似乎正在hit以下幾個方面:

  • 調用pop on deck直接修改了deck的 state。
  • 調用hit this.players[this.currentPlayer] (在Players.prototype.hit )直接修改Players中的播放器 object 。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM