【问题标题】:Why is my hooks states going back to its initial states?为什么我的钩子状态会回到初始状态?
【发布时间】:2022-11-30 10:15:43
【问题描述】:

我一直在制作一款游戏,最后要求用户输入他们的猜测。为了避免在我的实际项目中造成混淆,我在 codesandbox 中创建了一些东西来演示我遇到的问题。我应该补充一点,codesandbox 中的游戏没有多大意义。但本质上,您只需单击任何框 5 次即可生成一个随机数,当组件安装时,它还会创建一个包含 5 个随机数的数组。最后,您键入一个数字,它会检查两个数组是否都包含输入的键并相应地为它们着色。我遇到的问题是,一旦显示了猜测组件,所有挂钩状态都会返回到它们的初始状态。

主要.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

任何帮助将不胜感激!!!

【问题讨论】:

    标签: javascript reactjs typescript react-hooks react-typescript


    【解决方案1】:

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


    您误以为挂钩会跨组件共享状态。每次调用 useHook() 时,钩子都会有一个新的状态。要共享状态,您需要使用 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函数也有问题,这是一个很好的例子,说明你为什么需要输入您的参数. 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 ");
          }
        }
      };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-05-15
      • 1970-01-01
      • 2019-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-29
      • 1970-01-01
      相关资源
      最近更新 更多