gpt4 book ai didi

reactjs - 从深度嵌套的组件更新状态而不重新渲染父组件

转载 作者:行者123 更新时间:2023-12-04 11:48:47 26 4
gpt4 key购买 nike

input and map inside content, content inside page, page and button inside layout

我有一个或多或少结构如下的表单页面:

<Layout>
<Page>
<Content>
<Input />
<Map />
</Content>
</Page>
<Button />
</Layout>

Map 组件应该只渲染一次,因为在渲染时会触发一个动画。这意味着内容、页面和布局根本不应该重新渲染。

当输入为空时,应禁用布局内的按钮。 Input 的值不受 Content 控制,因为状态更改会导致重新渲染 Map。

我尝试了一些不同的东西(使用 refs、useImperativeHandle 等),但没有一个解决方案让我感觉很干净。在不更改布局、页面或内容状态的情况下,将输入状态连接到按钮状态的最佳方法是什么?请记住,这是一个相当小的项目,代码库使用“现代”React 实践(例如钩子(Hook)),并且没有像 Redux、MobX 等那样的全局状态管理。

最佳答案

这是一个避免重新渲染 Map 的示例( click here to play with it ) .但是,它重新渲染了其他组件,因为我通过了 children大约。但如果 map 是最重的,那应该可以解决问题。为避免渲染其他组件,您需要去掉 children prop 但这很可能意味着您将需要 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>
);
}

更新

下面是 version除了输入和按钮之外,上下文不会重新渲染组件:
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>
);
}

解决方案依赖于使用 memo避免在父级重新渲染时渲染并最小化传递给组件的属性数量。 Ref 仅用于渲染计数器

关于reactjs - 从深度嵌套的组件更新状态而不重新渲染父组件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60060672/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com