【问题标题】:React Typescript - Math.random gives wrong result even tho min value and max value is setReact Typescript - 即使设置了最小值和最大值,Math.random 也会给出错误的结果
【发布时间】:2021-06-12 07:12:12
【问题描述】:

主 TSX 文件

  const [minNumber, setMinNumber] = useLocalStorage('minRange', 1);
  const [maxNumber, setMaxNumber] = useLocalStorage('maxRange', 10);

...

  const getRandomNumber = () => {
    //Return a random number between minNumber and maxNumber:
    console.log("min: " + minNumber + " max: " + maxNumber)
    let randomNr = Math.floor(Math.random() * (maxNumber - minNumber + 1) + minNumber);
    setRandomNumber(randomNr);
  }

本地存储挂钩:

import { useState } from 'react';

export function useLocalStorage(key, defaultValue) {
    const getInitialValue = () => localStorage.getItem(key) ?? defaultValue;
    const [value, setValue] = useState(getInitialValue);
    const setAndStoreValue = (newValue) => {
        if (newValue !== '') {
            setValue(newValue);
            localStorage.setItem(key, newValue)
        }
    }
    return [value, setAndStoreValue];
};

演示问题。我创建了一个代码框链接: https://codesandbox.io/s/hdwqy?file=/src/App.tsx

如何重现问题:

  • 默认 minValue 为 1,maxValue 为 10
  • 将 minValue 设置为 8 和 maxValue 9(单击代码框中的“更改最小值和最大值”按钮)
  • 运行 getRandomNumber() 函数。 Outputs: 8 or 9 - 有效! (点击codeandbox中的“New random Number”按钮)
  • 刷新页面,你会得到存储在本地存储中的数据 min = 8, max = 9
  • 运行 getRandomNumber() 函数。 outputs 0 or 1 - 输出错误! (点击codeandbox中的“New random Number”按钮)
  • 问题在于,由于 min 和 max 之间的差为 2,因此它给出了 0 和 1。如果 min 为 8,max 为 10,那么它将输出 0、1 或 2。

我似乎无法弄清楚为什么会发生这种情况,因为如果我再次设置最小值和最大值并重新运行随机函数,它就可以正常工作。我还想提一下,在这两种情况下,console.log 都会输出min: 8 max: 9,因此本地存储似乎正在正确加载该值。这很奇怪。

【问题讨论】:

    标签: reactjs typescript random react-hooks local-storage


    【解决方案1】:

    问题可以简化为:

    const minNumber = '8';
    const maxNumber = '9';
    const getRandomNumber = () => {
      console.log("min: " + minNumber + " max: " + maxNumber);
      console.log('part', maxNumber - minNumber + 1);
      const result = Math.random() * 2 + '8';
      console.log(result);
    };
    
    getRandomNumber();

    本地存储值始终是字符串。这个:

    let randomNr = Math.floor(
      Math.random() * (maxNumber - minNumber + 1) + minNumber
    );
    

    变成,8和9:

    let randomNr = Math.floor(
      Math.random() * 2 + '8'
    );
    

    变成 0.2344581.63138 之类的东西 - + 将尾随 8 连接到 十进制 部分,然后 Math.floor 将其剃掉,所以你仍然留下一个 0 或 1 的数字。

    首先将存储值转换为数字,也许通过为useLocalStorage 提供映射器函数:

    export function useLocalStorage(key, defaultValue, mapper = str => str) {
        const getInitialValue = () => localStorage.getItem(key) !== null
          ? mapper(localStorage.getItem(key))
          : defaultValue;
        const [value, setValue] = useState(getInitialValue);
        const setAndStoreValue = (newValue) => {
            if (newValue !== '') {
                setValue(newValue);
                localStorage.setItem(key, newValue)
            }
        }
        return [value, setAndStoreValue];
    };
    
    const [minNumber, setMinNumber] = useLocalStorage('minRange', 1, Number);
    const [maxNumber, setMaxNumber] = useLocalStorage('maxRange', 10, Number);
    

    这个问题可以通过更多地使用 TypeScript 来避免,并正确键入变量(避免 any - 这会破坏 TypeScript 的观点) - minNumbermaxNumber 的类型是 字符串或数字 而不仅仅是一个数字会告诉你。

    也使用泛型:

    function useLocalStorage<T>(
      key: string,
      defaultValue: T,
      mapperToValue: (lsValue: string) => T,
      mapperToLS: (value: T) => string
    ) {
      const getInitialValue = () => {
        const lsValue = localStorage.getItem(key);
        return lsValue !== null ? mapperToValue(lsValue) : defaultValue;
      };
      const [value, setValue] = useState(getInitialValue);
      const setAndStoreValue = (newValue: T) => {
        setValue(newValue);
        localStorage.setItem(key, mapperToLS(newValue));
      };
      return [value, setAndStoreValue] as const;
    }
    
    export default function App() {
      const [minNumber, setMinNumber] = useLocalStorage("minRange", 1, Number, String);
      const [maxNumber, setMaxNumber] = useLocalStorage("maxRange", 10, Number, String);
      const [rndNumber, setRndNumber] = useState(0);
      // ...
    

    【讨论】:

      猜你喜欢
      • 2019-10-09
      • 2019-09-30
      • 1970-01-01
      • 2022-01-12
      • 1970-01-01
      • 1970-01-01
      • 2016-03-19
      • 2019-07-09
      • 2019-02-10
      相关资源
      最近更新 更多