React Typescript - 即使设置了最小值和最大值,Math.random 也会给出错误的结果
Posted
技术标签:
【中文标题】React Typescript - 即使设置了最小值和最大值,Math.random 也会给出错误的结果【英文标题】:React Typescript - Math.random gives wrong result even tho min value and max value is set 【发布时间】: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
,因此本地存储似乎正在正确加载该值。这很奇怪。
【问题讨论】:
【参考方案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.234458
或 1.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 的观点) - minNumber
和 maxNumber
的类型是 字符串或数字 而不仅仅是一个数字会告诉你。
也使用泛型:
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);
// ...
【讨论】:
以上是关于React Typescript - 即使设置了最小值和最大值,Math.random 也会给出错误的结果的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 React 和 TypeScript 设置 Electron?
react-redux 类型文件中的 TypeScript 错误
如何使用 Typescript 为 React 设置 Material-UI?