Joe*_*fei 6 reactjs next.js react-context react-state-management react-hooks
我有一个或多或少结构如下的表单页面:
<Layout>
<Page>
<Content>
<Input />
<Map />
</Content>
</Page>
<Button />
</Layout>
Run Code Online (Sandbox Code Playgroud)
Map 组件应该只渲染一次,因为在渲染时会触发一个动画。这意味着内容、页面和布局根本不应该重新渲染。
当输入为空时,应禁用布局内的按钮。Input 的值不受 Content 控制,因为状态更改会导致重新渲染 Map。
我尝试了一些不同的东西(使用 refs、useImperativeHandle 等),但没有一个解决方案让我感觉很干净。在不更改布局、页面或内容状态的情况下,将输入状态连接到按钮状态的最佳方法是什么?请记住,这是一个相当小的项目,代码库使用“现代”React 实践(例如钩子),并且没有像 Redux、MobX 等那样的全局状态管理。
下面是一个例子(点击这里发挥它)避免的重新渲染Map。但是,它会重新渲染其他组件,因为我会children四处走动。但如果地图是最重的,那应该可以解决问题。为了避免渲染其他组件,您需要摆脱childrenprop,但这很可能意味着您将需要 redux。您也可以尝试使用上下文,但我从未使用过它,因此不知道它通常会如何影响渲染
import React, { useState, useRef, memo } from "react";
import "./styles.css";
const GenericComponent = memo(
({ name = "GenericComponent", className, children }) => {
const counter = useRef(0);
counter.current += 1;
return (
<div className={"GenericComponent " + className}>
<div className="Counter">
{name} rendered {counter.current} times
</div>
{children}
</div>
);
}
);
const Layout = memo(({ children }) => {
return (
<GenericComponent name="Layout" className="Layout">
{children}
</GenericComponent>
);
});
const Page = memo(({ children }) => {
return (
<GenericComponent name="Page" className="Page">
{children}
</GenericComponent>
);
});
const Content = memo(({ children }) => {
return (
<GenericComponent name="Content" className="Content">
{children}
</GenericComponent>
);
});
const Map = memo(({ children }) => {
return (
<GenericComponent name="Map" className="Map">
{children}
</GenericComponent>
);
});
const Input = ({ value, setValue }) => {
const onChange = ({ target: { value } }) => {
setValue(value);
};
return (
<input
type="text"
value={typeof value === "string" ? value : ""}
onChange={onChange}
/>
);
};
const Button = ({ disabled = false }) => {
return (
<button type="button" disabled={disabled}>
Button
</button>
);
};
export default function App() {
const [value, setValue] = useState("");
return (
<div className="App">
<h1>SO Q#60060672</h1>
<Layout>
<Page>
<Content>
<Input value={value} setValue={setValue} />
<Map />
</Content>
</Page>
<Button disabled={value === ""} />
</Layout>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
以下是具有上下文的版本,除了输入和按钮外,不会重新渲染组件:
import React, { useState, useRef, memo, useContext } from "react";
import "./styles.css";
const ValueContext = React.createContext({
value: "",
setValue: () => {}
});
const Layout = memo(() => {
const counter = useRef(0);
counter.current += 1;
return (
<div className="GenericComponent">
<div className="Counter">Layout rendered {counter.current} times</div>
<Page />
<Button />
</div>
);
});
const Page = memo(() => {
const counter = useRef(0);
counter.current += 1;
return (
<div className="GenericComponent">
<div className="Counter">Page rendered {counter.current} times</div>
<Content />
</div>
);
});
const Content = memo(() => {
const counter = useRef(0);
counter.current += 1;
return (
<div className="GenericComponent">
<div className="Counter">Content rendered {counter.current} times</div>
<Input />
<Map />
</div>
);
});
const Map = memo(() => {
const counter = useRef(0);
counter.current += 1;
return (
<div className="GenericComponent">
<div className="Counter">Map rendered {counter.current} times</div>
</div>
);
});
const Input = () => {
const { value, setValue } = useContext(ValueContext);
const onChange = ({ target: { value } }) => {
setValue(value);
};
return (
<input
type="text"
value={typeof value === "string" ? value : ""}
onChange={onChange}
/>
);
};
const Button = () => {
const { value } = useContext(ValueContext);
return (
<button type="button" disabled={value === ""}>
Button
</button>
);
};
export default function App() {
const [value, setValue] = useState("");
return (
<div className="App">
<h1>SO Q#60060672, method 2</h1>
<p>
Type something into input below to see how rendering counters{" "}
<s>update</s> stay the same
</p>
<ValueContext.Provider value={{ value, setValue }}>
<Layout />
</ValueContext.Provider>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
解决方案依赖于memo避免在父级重新渲染时渲染并最小化传递给组件的属性数量。Ref 仅用于渲染计数器
| 归档时间: |
|
| 查看次数: |
2764 次 |
| 最近记录: |