React Typescript - Math.random 即使设置了最小值和最大值也会给出错误的结果

React Typescript - Math.random gives wrong result even tho min value and max value is set

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];
};

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

如何重现问题:

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

问题可以简化为:

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 连接到 decimal 部分,然后是 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 的要点) - minNumber 和 [=23= 的类型] 是一个 字符串或数字 而不仅仅是一个数字会让你失望。

也使用泛型:

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);
  // ...