React状态变更触发App组件重渲染的性能优化方案咨询
性能优化方案
如果你的项目当前组件层级简单,优先用第一种React.memo方案即可,改动成本最低,能直接解决绝大多数不必要重渲染的问题。Context方案更适合后续业务迭代、有更多子组件需要消费这两个状态的场景。
- 用
React.memo包裹无关联状态的组件
你当前的Navbar、Footer组件完全不依赖value、query两个状态,Sidebar接收的setQuery、setValue是useState返回的稳定引用,不会随状态变化而变更,所以给这三个组件都包裹一层React.memo,就能在App重渲染时跳过这几个组件的重渲染逻辑,大幅降低不必要的性能开销。
示例用法:// 对应组件的导出处修改,以Navbar为例 const Navbar = () => { /* 原有逻辑 */ } export default React.memo(Navbar) - 拆分状态为独立Context
把query、value以及对应的setter都封装到一个单独的Context Provider里,包裹需要消费这组状态的组件,不需要消费的组件(Navbar、Footer)完全不受状态变更影响,也不需要额外加memo就能避免重渲染。
示例实现:
之后修改App组件:// 新建SqlContext.js import { createContext, useContext, useState } from 'react' const SqlContext = createContext() export const SqlProvider = ({children}) => { const [query, setQuery] = useState(""); const [value, setValue] = useState("select * from customers"); return ( <SqlContext.Provider value={{query, setQuery, value, setValue}}> {children} </SqlContext.Provider> ) } export const useSql = () => useContext(SqlContext)
对应的Sidebar、Editor、TableSection组件直接用import { SqlProvider } from './SqlContext' const App = () => { return ( <div className="grid grid-cols-layout-desktop grid-rows-layout-desktop bg-gray-600 h-screen"> <Navbar /> <SqlProvider> <Sidebar /> <Suspense fallback={<div>Loading..</div>}> <Editor /> </Suspense> <TableSection /> </SqlProvider> <Footer /> </div> ) }useSql()钩子拿状态和setter即可,不需要再逐层传props,其中TableSection内部自行判断query是否存在再渲染内容。 - 高频输入场景加防抖优化
如果Editor是边输入边更新value,可以给onChange事件加300~500ms的防抖,减少状态更新的频率,进一步降低重渲染次数。
示例用法:// Editor组件内 import { debounce } from 'lodash' // 也可以自行实现简单防抖逻辑 const handleChange = debounce((newVal) => { setValue(newVal) }, 300) - React 18+ 可搭配使用useDeferredValue优化TableSection渲染
如果查询表格数据的逻辑比较重,输入时会卡顿,可以把传给TableSection的query用useDeferredValue包裹,让表格更新的优先级低于Editor的输入响应,避免输入卡帧:// TableSection组件内 const { query } = useSql() const deferredQuery = useDeferredValue(query) // 后续表格逻辑用deferredQuery代替原query即可
内容的提问来源于stack exchange,提问作者r121
相关产品推荐
相关产品推荐

