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

使用useRef结合useImperativeHandle时React不重新渲染的问题

问题原因

你当前的问题核心在于:App组件里的isCodeViewMode仅在初始渲染时通过ref获取一次值,之后MenuBar内部的状态更新不会触发App组件重渲染,导致App里的这个值始终停留在初始状态,无法同步MenuBar的最新变化。另外,useRef的current属性变更不会触发组件重渲染,就算后续调用getIsCodeViewMode,App也不会重新计算这个值。

解决方案

方案1:状态提升(最推荐)

把isCodeViewMode的状态从MenuBar移到App组件中,通过props将状态和更新方法传给MenuBar,这样状态变化会直接触发App重渲染,代码视图的类名也能实时更新。

修改App组件:

import { useState } from 'react';

// App组件内定义状态
const [isCodeViewMode, setIsCodeViewMode] = useState(false);

return (
    <div
        id="editor-container"
        className="ps-relative s-textarea p0 d-flex fd-column"
        style={{ width: "1500px", zIndex: 10 }}
    >
        <div className="js-sticky py6 bg-inherit btr-sm w100 ps-sticky t0 l0 z-nav s-editor-shadow js-plugin-container js-sticky">
            {/* 将状态和更新方法传入MenuBar */}
            <MenuBar 
                editor={editor as Editor} 
                isCodeViewMode={isCodeViewMode}
                setIsCodeViewMode={setIsCodeViewMode}
            />
        </div>
        <div
            id="editor-content"
            className="overflow-scroll fl-grow1 outline-none p12 pt6 w100 s-prose js-editor ProseMirror"
        >
            <EditorContent editor={editor} />
        </div>
        <div
            className={`mw-editor__codemirror ${isCodeViewMode ? "" : "d-none"}`}
        >
            <textarea></textarea>
        </div>
    </div>
);

修改MenuBar组件:

移除内部的useState和useImperativeHandle,直接使用props传递的值和方法:

interface MenuBarProps {
    editor: Editor;
    isCodeViewMode: boolean;
    setIsCodeViewMode: (value: boolean) => void;
}

const MenuBar: React.FC<MenuBarProps> = ({ editor, isCodeViewMode, setIsCodeViewMode }) => {
    // 切换视图时直接调用props中的更新方法
    const toggleCodeView = () => {
        setIsCodeViewMode(!isCodeViewMode);
    };

    return (
        // 你的MenuBar结构,按钮点击绑定toggleCodeView
        <button onClick={toggleCodeView}>
            {isCodeViewMode ? "切换到富文本视图" : "切换到代码视图"}
        </button>
    );
};

方案2:回调函数同步状态(需保留MenuBar内部状态时使用)

如果必须把状态留在MenuBar内,可以让MenuBar接收一个回调函数,当内部状态变化时调用该回调,通知App更新自身状态:

修改App组件:

import { useState } from 'react';

const [isCodeViewMode, setIsCodeViewMode] = useState(false);

// 定义回调函数,接收MenuBar传来的最新状态
const handleCodeViewChange = (newMode: boolean) => {
    setIsCodeViewMode(newMode);
};

return (
    <div
        id="editor-container"
        className="ps-relative s-textarea p0 d-flex fd-column"
        style={{ width: "1500px", zIndex: 10 }}
    >
        <div className="js-sticky py6 bg-inherit btr-sm w100 ps-sticky t0 l0 z-nav s-editor-shadow js-plugin-container js-sticky">
            <MenuBar 
                editor={editor as Editor} 
                onCodeViewChange={handleCodeViewChange}
            />
        </div>
        <div
            id="editor-content"
            className="overflow-scroll fl-grow1 outline-none p12 pt6 w100 s-prose js-editor ProseMirror"
        >
            <EditorContent editor={editor} />
        </div>
        <div
            className={`mw-editor__codemirror ${isCodeViewMode ? "" : "d-none"}`}
        >
            <textarea></textarea>
        </div>
    </div>
);

修改MenuBar组件:

interface MenuBarProps {
    editor: Editor;
    onCodeViewChange: (mode: boolean) => void;
}

const MenuBar: React.FC<MenuBarProps> = ({ editor, onCodeViewChange }) => {
    const [isCodeViewMode, setIsCodeViewMode] = useState(false);

    const toggleCodeView = () => {
        const newMode = !isCodeViewMode;
        setIsCodeViewMode(newMode);
        // 调用回调通知App更新状态
        onCodeViewChange(newMode);
    };

    // 若其他场景仍需要ref暴露方法,可保留useImperativeHandle
    // useImperativeHandle(ref, () => ({ ... }), [isCodeViewMode]);

    return (
        <button onClick={toggleCodeView}>
            {isCodeViewMode ? "切换到富文本视图" : "切换到代码视图"}
        </button>
    );
};
原方案失效的核心原因

App组件中isCodeViewMode = menuBarRef.current?.getIsCodeViewMode()这行代码,仅在组件每次渲染时执行一次。而MenuBar内部状态变化不会主动触发App重渲染,因此App不会重新执行这行代码去获取最新值,自然无法同步状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 08:28:45