删除组件后如何清理react js中的useEffect函数
how to cleanup the useEffect function in react js after removing component
我在 React js 中使用 useRef 和 useEffect 时遇到这个错误。
**我如何清理 React js 中的 useEffect 这是所有问题的主题 **
Dropdown.js:9
Uncaught TypeError: Cannot read properties of null (reading 'contains')
at HTMLDocument.bodydroptoggler (Dropdown.js:9)
截图如下:
当我点击名为“drop toggler”的按钮时出现此错误
这里是app.js
的代码
import React, { useState } from "react";
import Dropdown from "./components/Dropdown";
const options = [
{
label: "red color is selected",
value: "red",
},
{
label: "blue color is selected",
value: "blue",
},
{
label: "green color is seleted",
value: "green",
},
];
const App = () => {
const [dropactive, setDropactive] = useState(true);
return (
<div className="container ui">
<button
className="button ui"
onClick={() => setDropactive(!dropactive)}
>
drop toggler
</button>
{dropactive ? <Dropdown options={options} /> : null}
</div>
);
};
export default App;
这里是dropdown.js
的代码
import React, { useState, useRef, useEffect } from "react";
const Dropdown = ({ options }) => {
const [selected, setSelected] = useState(options[0]);
const [open, setOpen] = useState(false);
const ref = useRef();
useEffect(() => {
const bodydroptoggler = (event) => {
if (ref.current.contains(event.target)) {
return;
}
setOpen(false);
};
document.addEventListener("click", bodydroptoggler);
return () => {
document.removeEventListener("click", bodydroptoggler);
console.log("work");
};
}, []);
const RenderedOptions = options.map((option, index) => {
if (selected.value === option.value) {
return null;
} else {
return (
<div
className="item"
key={index}
onClick={() => {
setSelected(option);
}}
>
{option.label}
</div>
);
}
});
return (
<div ref={ref} className="ui form">
<div className="field">
<label className="text label">Select from here:</label>
<div
className={`ui selection dropdown ${
open ? "active visible" : ""
}`}
onClick={() => setOpen(!open)}
>
<i className="dropdown icon"></i>
<div className="text">{selected.label}</div>
<div className={`menu ${open ? "visible transition" : ""}`}>
{RenderedOptions}
</div>
</div>
</div>
</div>
);
};
export default Dropdown;
这是我要执行的操作
我只想通过单击按钮隐藏该表单。
你怎么能运行这个项目
- 只需创建一个 React 应用程序
- 将 app.js 的代码放入您项目的 app.js
- dropdown.js 组件文件夹内
我希望所有的细节都能对你有所帮助,我还需要更多的东西,请下线
提前致谢
您是否尝试过使用可选链接,因为 ref.current 有时可能未定义?
if (ref.current?.contains(event.target))
这里是 codesandbox link 修复程序。
还有一些来自 React Ref docs 的额外上下文,说明为什么有时 ref 可能为 null
React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts.
编辑:
这就是 useLayoutEffect
的目的。它运行它的内容(和清理)同步并且避免了竞争条件。这是证明这一点的 stackblitz:
https://stackblitz.com/edit/react-5w7vog
也请查看 Kent Dodd 的 this post:
One other situation you might want to use useLayoutEffect instead of useEffect is if you're updating a value (like a ref) and you want to make sure it's up-to-date before any other code runs. For example:
原始答案
这很复杂。您的代码通常看起来不错,所以我花了一分钟时间才明白为什么。但这里是 为什么 - Dropdown
组件卸载 在 效果清理之前 运行。所以点击事件仍然找到处理程序,这次是对 ref 的空引用(因为 ref 会立即更新)。
你的代码是正确的,同理 React - 但这是一个需要更深入理解的边缘案例。
正如其他回答者已经提到的,只需添加一个可选检查。但我想你可能想知道为什么。
我在 React js 中使用 useRef 和 useEffect 时遇到这个错误。 **我如何清理 React js 中的 useEffect 这是所有问题的主题 ** Dropdown.js:9
Uncaught TypeError: Cannot read properties of null (reading 'contains')
at HTMLDocument.bodydroptoggler (Dropdown.js:9)
截图如下:
当我点击名为“drop toggler”的按钮时出现此错误
这里是app.js
的代码import React, { useState } from "react";
import Dropdown from "./components/Dropdown";
const options = [
{
label: "red color is selected",
value: "red",
},
{
label: "blue color is selected",
value: "blue",
},
{
label: "green color is seleted",
value: "green",
},
];
const App = () => {
const [dropactive, setDropactive] = useState(true);
return (
<div className="container ui">
<button
className="button ui"
onClick={() => setDropactive(!dropactive)}
>
drop toggler
</button>
{dropactive ? <Dropdown options={options} /> : null}
</div>
);
};
export default App;
这里是dropdown.js
的代码import React, { useState, useRef, useEffect } from "react";
const Dropdown = ({ options }) => {
const [selected, setSelected] = useState(options[0]);
const [open, setOpen] = useState(false);
const ref = useRef();
useEffect(() => {
const bodydroptoggler = (event) => {
if (ref.current.contains(event.target)) {
return;
}
setOpen(false);
};
document.addEventListener("click", bodydroptoggler);
return () => {
document.removeEventListener("click", bodydroptoggler);
console.log("work");
};
}, []);
const RenderedOptions = options.map((option, index) => {
if (selected.value === option.value) {
return null;
} else {
return (
<div
className="item"
key={index}
onClick={() => {
setSelected(option);
}}
>
{option.label}
</div>
);
}
});
return (
<div ref={ref} className="ui form">
<div className="field">
<label className="text label">Select from here:</label>
<div
className={`ui selection dropdown ${
open ? "active visible" : ""
}`}
onClick={() => setOpen(!open)}
>
<i className="dropdown icon"></i>
<div className="text">{selected.label}</div>
<div className={`menu ${open ? "visible transition" : ""}`}>
{RenderedOptions}
</div>
</div>
</div>
</div>
);
};
export default Dropdown;
这是我要执行的操作 我只想通过单击按钮隐藏该表单。
你怎么能运行这个项目
- 只需创建一个 React 应用程序
- 将 app.js 的代码放入您项目的 app.js
- dropdown.js 组件文件夹内
我希望所有的细节都能对你有所帮助,我还需要更多的东西,请下线 提前致谢
您是否尝试过使用可选链接,因为 ref.current 有时可能未定义?
if (ref.current?.contains(event.target))
这里是 codesandbox link 修复程序。
还有一些来自 React Ref docs 的额外上下文,说明为什么有时 ref 可能为 null
React will assign the current property with the DOM element when the component mounts, and assign it back to null when it unmounts.
编辑:
这就是 useLayoutEffect
的目的。它运行它的内容(和清理)同步并且避免了竞争条件。这是证明这一点的 stackblitz:
https://stackblitz.com/edit/react-5w7vog
也请查看 Kent Dodd 的 this post:
One other situation you might want to use useLayoutEffect instead of useEffect is if you're updating a value (like a ref) and you want to make sure it's up-to-date before any other code runs. For example:
原始答案
这很复杂。您的代码通常看起来不错,所以我花了一分钟时间才明白为什么。但这里是 为什么 - Dropdown
组件卸载 在 效果清理之前 运行。所以点击事件仍然找到处理程序,这次是对 ref 的空引用(因为 ref 会立即更新)。
你的代码是正确的,同理 React - 但这是一个需要更深入理解的边缘案例。
正如其他回答者已经提到的,只需添加一个可选检查。但我想你可能想知道为什么。