[英]React hooks cause unintentional re-render
I am working with a React + Leaflet map and noticing the map container / elements re-render any time I show or close a modal.我正在使用 React + Leaflet map 并注意到 map 容器/元素在我显示或关闭模式时重新渲染。
I have created a sandbox to demonstrate the problem, but this occurs in other places throughout my app if additional examples would help.我创建了一个沙箱来演示该问题,但如果其他示例有帮助,这会在我的应用程序中的其他地方发生。
https://codesandbox.io/s/elegant-rain-01f9l?file=/src/App.jshttps://codesandbox.io/s/elegant-rain-01f9l?file=/src/App.js
From reading alternative SO posts, such as this very similar one , I recognize this is likely caused by my hooks (ex. handleShow/setShow) which force the entire component to re-render.通过阅读替代 SO 帖子,例如这个非常相似的帖子,我认识到这可能是由我的钩子(例如 handleShow/setShow)引起的,它强制整个组件重新渲染。 The unintended behavior is noticed as follows:
意外行为如下所示:
If you drag the map so that the current location is out of view and open a modal, we force the re-load of <LeafletControlGeocoder/>
and <LocationMarker/>
.如果拖动 map 使当前位置不在视野范围内并打开模态框,我们会强制重新加载
<LeafletControlGeocoder/>
和<LocationMarker/>
。 This is evident because the map re-pans to the current location, and a new 'search icon' appears in the top right on the map.这很明显,因为 map 会重新平移到当前位置,并且 map 的右上角会出现一个新的“搜索图标”。
Steps to replicate:复制步骤:
*If you notice an issue in sandbox related to react-bootstrap/Modal, just update the dependency to latest (refresh icon) - this is a weird sandbox issue but unrelated to my question. *如果您在沙箱中发现与 react-bootstrap/Modal 相关的问题,只需将依赖项更新为最新(刷新图标) - 这是一个奇怪的沙箱问题,但与我的问题无关。
The issue is caused by having some child components function defined within the body of another React functional component.该问题是由于在另一个 React 功能组件的主体中定义了一些子组件 function 引起的。
function App() { // A React functional component
const [show, setShow] = useState(false);
// etc.
// A child React functional component in the body of another component...
function LocationMarker() {
const [position, setPosition] = useState(null);
// etc.
}
// Another child component
function LeafletControlGeocoder() {
useEffect(() => {}, []);
// etc.
}
return (
<>
{/* More content... */}
<MapContainer center={[45.4, -75.7]} zoom={12}>
<LeafletControlGeocoder />
<LocationMarker />
</MapContainer>
</>
);
}
This may not be problematic if your child components are stateless (no hook).如果您的子组件是无状态的(没有挂钩),这可能不会有问题。 In that case they are more like "sub-templates".
在这种情况下,它们更像是“子模板”。
But if those child components do use some hooks, then being in the body of another functional component will interfere with how the hooks work: because the child component function is re-created at each re-render, React has trouble identifying those children as being the same component, and ends up duplicating their output.但是如果这些子组件确实使用了一些钩子,那么在另一个功能组件的主体中会干扰钩子的工作方式:因为子组件 function 在每次重新渲染时都会重新创建,React 无法识别这些子组件是相同的组件,最终复制了他们的 output。
Simply make sure not to define some Functional Components within another one, but always at the top-level of your scope (typically at the root of your file).只需确保不要在另一个中定义一些功能组件,而是始终在 scope 的顶层(通常在文件的根目录)。 As mentioned in the question comments, a standard practice is simply to have 1 component per file.
如问题评论中所述,标准做法是每个文件只有一个组件。
function App() { // A React functional component
const [show, setShow] = useState(false);
// etc.
return (
<>
{/* More content... */}
<MapContainer center={[45.4, -75.7]} zoom={12}>
<LeafletControlGeocoder />
<LocationMarker />
</MapContainer>
</>
);
}
// Another React functional component at top scope level
function LocationMarker() {
const [position, setPosition] = useState(null);
// etc.
}
// Another component
function LeafletControlGeocoder() {
useEffect(() => {}, []);
// etc.
}
Fixed app: https://codesandbox.io/s/lively-monad-yve67固定应用程序: https://codesandbox.io/s/lively-monad-yve67
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.