繁体   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