英文:
react function running twice thrice | ts
问题
这里大家好。我有一个下拉组件,在其中我传递了选项,当点击这些选项时,我使用R3F导入3D模型。它工作得很好,但唯一的问题是当页面第一次加载时,前2次或4次点击会导入完全随机的模型,这不是我打算导入的模型,但它正在发生。请看一下下面的代码,看看有什么问题。
import {
useState,
useEffect,
useRef,
Dispatch,
SetStateAction,
} from "react";
const useOnClickOutside =
ref: React.RefObject
handler: () => void
) => {
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
handler();
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref, handler]);
};
interface Option {
name: string;
value: string | number;
image: string;
id: string;
}
interface DropdownProps {
options: Option[];
title: string;
xAxis: number;
yAxis: number;
zAxis: number;
SysmexArray: number[][];
setSysmexArray: Dispatch<SetStateAction<number[][]>>;
cr10_no_7thArray: number[][];
setCr10_no_7thArray: Dispatch<SetStateAction<number[][]>>;
ID: string;
setID: Dispatch<SetStateAction
}
const Dropdown: React.FC
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState<Option | undefined>(
undefined
);
const dropdownRef = useRef
const toggleDropdown = () => setIsOpen(!isOpen);
useOnClickOutside(dropdownRef, () => setIsOpen(false));
useEffect(() => {
const handleEscapeKeyPress = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setIsOpen(false);
}
};
document.addEventListener("keydown", handleEscapeKeyPress);
return () => {
document.removeEventListener("keydown", handleEscapeKeyPress);
};
}, []);
/**/
/这个函数没有正常工作 /
/ */
const handleOptionClick = (option: Option) => {
setSelectedOption(option);
setIsOpen(false);
if (selectedOption?.name === "m-st") {
props.setID(() =>{
props.setSysmexArray(() => [
...props.SysmexArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return "m-st"});
}
if (selectedOption?.name === "CR10") {
props.setID(() => {
props.setCr10_no_7thArray(() => [
...props.cr10_no_7thArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return "r-cr10"});
}
};
return (
{isOpen && (
-
{props.options.map((option) => (
<li
key={option.value}
className="flex flex-col justify-center items-center px-4 py-2 text-sm text-gray-700 cursor-pointer hover:bg-gray-100"
onClick={() => handleOptionClick(option)}
>
{" "}
<div className="text-center">{option.name}</div>
</li>
))}
</ul>
</div>
)}
</div>
);
};
export default Dropdown;
英文:
Here there everyone. I've a dropdown component in which I'm passing options and on clicking of those options I'm importing 3d models with R3F. so its working fine but the only catch is when the page loads for the first time first 2 or 4 clicks import totally random models ones that I dont indent to import but its happening. below is the code please take a look what's wrong with it.
import {
useState,
useEffect,
useRef,
Dispatch,
SetStateAction,
} from "react";
const useOnClickOutside = <T extends HTMLElement>(
ref: React.RefObject<T>,
handler: () => void
) => {
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (ref.current && !ref.current.contains(event.target as Node)) {
handler();
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [ref, handler]);
};
interface Option {
name: string;
value: string | number;
image: string;
id: string;
}
interface DropdownProps {
options: Option[];
title: string;
xAxis: number;
yAxis: number;
zAxis: number;
SysmexArray: number[][];
setSysmexArray: Dispatch<SetStateAction<number[][]>>;
cr10_no_7thArray: number[][];
setCr10_no_7thArray: Dispatch<SetStateAction<number[][]>>;
ID: string;
setID: Dispatch<SetStateAction<string>>;
}
const Dropdown: React.FC<DropdownProps> = (props) => {
const [isOpen, setIsOpen] = useState(false);
const [selectedOption, setSelectedOption] = useState<Option | undefined>(
undefined
);
const dropdownRef = useRef<HTMLDivElement>(null);
const toggleDropdown = () => setIsOpen(!isOpen);
useOnClickOutside(dropdownRef, () => setIsOpen(false));
useEffect(() => {
const handleEscapeKeyPress = (event: KeyboardEvent) => {
if (event.key === "Escape") {
setIsOpen(false);
}
};
document.addEventListener("keydown", handleEscapeKeyPress);
return () => {
document.removeEventListener("keydown", handleEscapeKeyPress);
};
}, []);
/****************************************/
/*THIS FUNCTION IS NOT WORKING PROPERLY */
/**************************************** */
const handleOptionClick = (option: Option) => {
setSelectedOption(option);
setIsOpen(false);
if (selectedOption?.name === "m-st") {
props.setID(() =>{
props.setSysmexArray(() => [
...props.SysmexArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return"m-st"});
}
if (selectedOption?.name === "CR10") {
props.setID(() => {
props.setCr10_no_7thArray(() => [
...props.cr10_no_7thArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return"r-cr10"});
}
};
return (
<div className="relative pl-0" ref={dropdownRef}>
<button
type="button"
className="flex items-center justify-between w-full px-4 py-2 text-sm font-medium text-gray-700 bg-white border border-gray-300 rounded-md shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
onClick={toggleDropdown}
>
{selectedOption ? (
<>
{props.title}
{console.log(`${selectedOption.name} : ${selectedOption.value}`)}
</>
) : (
props.title
)}
<svg
className={`w-5 h-5 ml-2 transition-transform ${
isOpen ? "transform rotate-180" : ""
}`}
viewBox="0 0 20 20"
fill="currentColor"
aria-hidden="true"
>
<path
fillRule="evenodd"
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
clipRule="evenodd"
/>
</svg>
</button>
{isOpen && (
<div className="absolute z-10 w-full mt-2 bg-white rounded-md shadow-lg">
<ul className="py-1">
{props.options.map((option) => (
<li
key={option.value}
className="flex flex-col justify-center items-center px-4 py-2 text-sm text-gray-700 cursor-pointer hover:bg-gray-100"
onClick={() => handleOptionClick(option)}
>
<img
src={option.image}
height={100}
width={100}
alt={option.name}
/>{" "}
<div className="text-center">{option.name}</div>
</li>
))}
</ul>
</div>
)}
</div>
);
};
export default Dropdown;
I've tried changing dependecy arrrays of useEffect, using useCallback to make sure it fire only what is got clicked but neither of them worked for me.
答案1
得分: 2
Use option
参数而不是selectedOption
状态,否则您的函数将使用先前的selectedOption
值。此外,我们不知道setID
函数确切是做什么的,所以这只是一次尝试。但是,请尝试以下内容,看看是否有效。
const handleOptionClick = (option: Option) => {
setSelectedOption(option);
setIsOpen(false);
if (option?.name === "m-st") {
props.setID(() => {
props.setSysmexArray(() => [
...props.SysmexArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return "m-st";
});
}
if (option?.name === "CR10") {
props.setID(() => {
props.setCr10_no_7thArray(() => [
...props.cr10_no_7thArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return "r-cr10";
});
}
};
英文:
Use option
argument instead of selectedOption
state otherwise your function will use previous value of selectedOption
. Also we don't know what setID
function exactly does so this is a shot in dark. But try below and see if it works.
const handleOptionClick = (option: Option) => {
setSelectedOption(option);
setIsOpen(false);
if (option?.name === "m-st") {
props.setID(() =>{
props.setSysmexArray(() => [
...props.SysmexArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return"m-st"});
}
if (option?.name === "CR10") {
props.setID(() => {
props.setCr10_no_7thArray(() => [
...props.cr10_no_7thArray,
[props.xAxis, props.yAxis, props.zAxis],
]);
return"r-cr10"});
}
};
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
- react-hooks
- react-three-fiber
- reactjs
- typescript
评论