簡體   English   中英

為什么我的鈎子狀態會回到初始狀態?

[英]Why is my hooks states going back to its initial states?

我一直在制作一款游戲,最后要求用戶輸入他們的猜測。 為了避免在我的實際項目中造成混淆,我在 codesandbox 中創建了一些東西來演示我遇到的問題。 我應該補充一點,codesandbox 中的游戲沒有多大意義。 但本質上,您只需單擊任何框 5 次即可生成一個隨機數,當組件安裝時,它還會創建一個包含 5 個隨機數的數組。 最后,您鍵入一個數字,它會檢查 arrays 是否包含輸入的密鑰,並相應地檢查 colors 是否包含它們。 我遇到的問題是,一旦顯示了猜測組件,所有掛鈎狀態都會返回到它們的初始狀態。

主要.tsx

import { Guess } from "./Guess";
import { useHook } from "./Hook";
import { Loading } from "./Loading";
import "./styles.css";

export const Main = () => {
  const {loading, count, handleClick, randArr} = useHook()

  return (
    <div className="main">
      {!loading && count < 5 &&
      <div className='click-container'>
          {Array.from({length: 5}).fill('').map((_, i: number) =>
            <div onClick={handleClick} className='box' key={i}>Click</div>
          )}
      </div>
      }
      {loading && <Loading count={count} />}
      {!loading && count >= 5 && <Guess arr={randArr} />}
    </div>
  );
}

鈎子.tsx

import { useEffect, useState } from 'react'

export const useHook = () => {
  type guessType = {
    keyNum: number
    isContain: boolean
  }

  const [disable, setDisable] = useState(true)
  const [randArr, setRandArr] = useState<number[]>([])
  const [initialArr, setInitialArr] = useState<number[]>([])
  const [count, setCount] = useState<number>(0)
  const [loading, setLoading] = useState(true)
  const [guess, setGuess] = useState<guessType[]>([])

  const randomNum = () => {
    return Math.floor(Math.random() * (9 - 0 + 1) + 0);
  }

  useEffect(() => {
    const handleInitialArr = () => {
      for (let i = 0; i < 5; i++) {
        let num = randomNum()
        setInitialArr((prev) => [...prev, num])
      }
    }
    handleInitialArr()
  }, [])

  const handleClick = () => {
    if (!disable) {
      let num = randomNum()
      setRandArr((prev)=> [...prev, num])
      setCount((prev) => prev + 1)
      setDisable(true)
      setLoading(true)
    }
  }

  useEffect(()=> {
    const handleLoading = () => {
      setTimeout(() => {
        setLoading(false)
      }, 500)
    }

    const handleRound = () => {
      setDisable(false)
    }

    handleLoading()
    handleRound()
  }, [count])

  const handleKeyUp = ({key}) => {
    const isNumber = /^[0-9]$/i.test(key)
    if (isNumber) {
      if (randArr.includes(key) && initialArr.includes(key)) {
        setGuess((prev) => [...prev, {keyNum: key, isContain: true}])
        console.log(' they both have this number')
      } else {
        setGuess((prev) => [...prev, {keyNum: key, isContain: false}])
        console.log(' they both do not contain this number ')
      }
    }
  }

  console.log(count)
  console.log(randArr, ' this is rand arr')
  console.log(initialArr, ' this is initial arr')
  return {
    count, 
    loading,
    handleClick, 
    randArr,
    handleKeyUp,
    guess
  }
}

猜猜.tsx

import React, { useEffect } from "react";
import { useHook } from "./Hook";
import "./styles.css";

type props = {
  arr: number[];
};

export const Guess: React.FC<props> = (props) => {
  const { handleKeyUp, guess } = useHook();

  useEffect(() => {
    window.addEventListener("keyup", handleKeyUp);

    return () => {
      window.removeEventListener("keyup", handleKeyUp);
    };
  }, [handleKeyUp]);

  console.log(props.arr, " this is props arr ");
  return (
    <div className="content">
      <div>
        <p>Guesses: </p>
        <div className="guess-list">
          {guess.map((item: any, i: number) =>
            <p key={i} className={guess[i].isContain ? 'guess-num-true': 'guess-num-false'} >{item.keyNum}</p>
          )}
        </div>
      </div>
    </div>
  );
};

另外,如果你想自己看看,這里是 codesandbox: https://codesandbox.io/s/guess-numbers-70fss9

任何幫助將不勝感激!!!

固定演示: https://codesandbox.io/s/guess-numbers-fixed-kz3qmw?file=/src/my-context.tsx:1582-2047


您誤以為掛鈎在組件之間共享 state。 每次調用useHook()時,鈎子都會有一個新的 state。 要共享 state,您需要使用Context

type guessType = {
  keyNum: number;
  isContain: boolean;
};

type MyContextType = {
  count: number;
  loading: boolean;
  handleClick: () => void;
  randArr: number[];
  handleKeyUp: ({ key: string }) => void;
  guess: guessType[];
};

export const MyContext = createContext<MyContextType>(null as any);

export const MyContextProvider: FC<PropsWithChildren<{}>> = ({ children }) => {
  
  // Same stuff as your hook goes here

  return (
    <MyContext.Provider
      value={{ count, loading, handleClick, randArr, handleKeyUp, guess }}
    >
      {children}
    </MyContext.Provider>
  );
};
export const App = () => {
  return (
    <div className="App">
      <MyContextProvider>
        <Page />
      </MyContextProvider>
    </div>
  );
};
export const Main = () => {
  const { loading, count, handleClick, randArr } = useContext(MyContext);
  ...
}
export const Guess: React.FC<props> = (props) => {
  const { handleKeyUp, guess } = useContext(MyContext);
  ...
}

你的handleKeyUp function 也被竊聽了,這是一個很好的例子,說明為什么你需要輸入你的參數 key是字符串,不是數字。 所以條件永遠是假的。

  const handleKeyUp = ({ key }: {key: string}) => {
    const num = parseInt(key);
    if (!isNaN(num)) {
      if (randArr.includes(num) && initialArr.includes(num)) {
        setGuess((prev) => [...prev, { keyNum: num, isContain: true }]);
        console.log(" they both have this number");
      } else {
        setGuess((prev) => [...prev, { keyNum: num, isContain: false }]);
        console.log(" they both do not contain this number ");
      }
    }
  };

暫無
暫無

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

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