You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React字体大小调整组件localStorage初始化取值异常问题求助

问题原因

  • state类型不统一:初始给useState传的是数字类型的defaultFont,但后续所有setFontSize调用都传入{fontSize: 数值}的对象类型,导致后续字体大小对比、样式拼接逻辑全部异常。
  • getTextSize逻辑完全错误:React的setState类方法都是无返回值的异步函数,你将setFontSize的返回值赋值给fontSize变量,拿到的只会是undefined,parseInt转换后就是NaN,自然无法拿到正确值。此外else分支中你给setFontSize传入的fontSize是刚定义未赋值的变量,值为undefined。
  • localStorage类型未转换:localStorage中存储的所有值都是字符串类型,直接读取后做数值运算会出现类型错误。
  • 初始化时机过晚:你等到useEffect执行才读取localStorage赋值,其实可以直接把初始化逻辑放到useState的入参函数中,组件挂载第一时间就能拿到正确值。

修复后完整代码

import React, { useState, useEffect, useCallback } from "react";
import PropTypes from "prop-types";

const TextResizer = ({
  defaultFont,
  step,
  min,
  max,
  suffix,
  store,
  storeKey
}) => {
  // 初始化时直接读取localStorage,转成数字,不存在则用默认值
  const [fontSize, setFontSize] = useState(() => {
    if (store && store.getItem(storeKey)) {
      const savedSize = parseInt(store.getItem(storeKey), 10);
      // 加边界判断,避免存储的值超出min/max范围
      return isNaN(savedSize) ? defaultFont : Math.min(Math.max(savedSize, min), max);
    }
    return defaultFont;
  });

  const toggle = useCallback((type) => {
    let newFontSize = fontSize;
    switch (type) {
      case "increase":
        newFontSize = Math.min(fontSize + step, max);
        break;
      case "decrease":
        newFontSize = Math.max(fontSize - step, min);
        break;
      default:
        newFontSize = defaultFont;
        break;
    }
    setFontSize(newFontSize);
    store.setItem(storeKey, newFontSize);
  }, [fontSize, step, min, max, defaultFont, store, storeKey]);

  // 字体大小变化时同步更新全局样式
  useEffect(() => {
    document.documentElement.style.fontSize = `${fontSize}${suffix}`;
  }, [fontSize, suffix]);

  return (
    <React.Fragment>
      <button disabled={fontSize <= min} onClick={() => toggle("decrease")}>
       decrease
      </button>
      <button onClick={() => toggle("default")}>default</button>
      <button disabled={fontSize >= max} onClick={() => toggle("increase")}>
        increase
      </button>
    </React.Fragment>
  );
};
TextResizer.propTypes = {
  defaultFont: PropTypes.number,
  step: PropTypes.number,
  min: PropTypes.number,
  max: PropTypes.number,
  suffix: PropTypes.string,
  store: PropTypes.object,
  storeKey: PropTypes.string
};
TextResizer.defaultProps = {
  defaultFont: 100,
  step: 20,
  min: 60,
  max: 180,
  suffix: "%",
  store: typeof window !== 'undefined' ? window.localStorage : null,
  storeKey: "TextResizer"
};
export default TextResizer;

额外优化说明

  • 用useCallback缓存toggle函数,避免不必要的重渲染
  • 把全局样式更新单独放到useEffect中,逻辑更清晰,避免每次渲染都插入新的style标签
  • 存储默认值增加了服务端渲染兼容判断,避免SSR场景下找不到window报错
  • 加减字体时直接做边界限制,避免存储超出范围的数值

内容的提问来源于stack exchange,提问作者Digital Legend

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 04:39:03