react-select 不 "fire" `onChange` 处理程序
react-select does not "fire" the `onChange` handler
我有一个 DropDown
组件,它呈现 react-select
下拉菜单并使用自定义挂钩 open/close。
自定义挂钩
import { useState, useRef, useEffect } from 'react';
const useCloseOnClickOutside = (initialState) => {
const [isVisible, setIsVisible] = useState(initialState);
const ref = useRef(null);
/**
* Attach Event Listeners
*/
useEffect(() => {
document.addEventListener('click', handleClick, true);
document.addEventListener('touchstart', handleClick, true);
return () => {
document.removeEventListener('click', handleClick, true);
document.removeEventListener('touchstart', handleClick, true);
};
},[]);
const handleClick = (event) => {
if (!ref.current)
return;
// If someone clicks outside the component close the state
if (!ref.current?.contains(event.target)) {
setIsVisible(false);
} else {
// If someone click on the component toggle the state
setIsVisible((prevState => !prevState));
}
};
return {
ref,
isVisible
};
};
export default useCloseOnClickOutside;
下拉菜单
import React from 'react';
import Select from 'react-select';
import useCloseOnClickOutside from '../../hooks/useCloseOnClickOutside';
const Dropdown = ({handleChange, defaultValue, options, value}) => {
const {ref,isVisible} = useCloseOnClickOutside(false);
return (
<div ref={ref}>
<Select
options={options}
onChange={handleChange}
defaultValue={defaultValue}
value={value}
menuIsOpen={isVisible}
/>
</div>
);
};
我将 ref
从 useCloseOnClickOutside
传递到 Select
的外部 div 以捕获气泡事件。
我传递给 Select
onChange
的 handleChange
回调目前什么都不做:
const handleChange = (val) => console.log(val)
并这样称呼它:
父组件
const ParentComponent = () => {
// All theese are just mocked data
const mockedOptions = [];
const handleChange = (val) => console.log(val);
const mockedDefaultValue = 'default-value';
const mockedValue = stateValue;
return (
<Dropdown
handleChange={handleChange}
options={mockedOptions}
defaultValude={mockedDefaultValue}
value={mockedValue}
/>
)
}
问题是,在我将 ref
传递给父 div 的那一刻,onChange
根本没有触发。如果我删除它,它会成功运行。我找不到发生这种情况的任何理由。这可能是 react-select
的问题吗??
我认为你必须在 react-select 触发 onChange
事件后将 menuIsOpen
设置为 false。
看起来如果 select 被隐藏,那么 onChange
事件不会被触发
因此,您可能需要为自定义挂钩添加延迟。然后 select 将在触发 onChange
后立即隐藏
setTimeout(() => setIsVisible(false));
////
setTimeout(() => setIsVisible((prevState => !prevState)));
PS:我不确定您是否需要自定义挂钩来决定 select 的打开状态,因为这是 react-select[= 的默认行为15=]
我看到问题是您在 addEventListener
中使用了 capture
pharse。所以 setIsVisible(false);
会在 onChange
之前被调用。所以当 select 被隐藏时 onChange
将不会调用。
我看到你有两个解决方案要解决。
删除capture
阶段:
document.addEventListener("click", handleClick);
或延迟 setTimeOut 以确保它在 onChange
:
之后调用
setTimeout(() => setIsVisible(false), 0);
我有一个 DropDown
组件,它呈现 react-select
下拉菜单并使用自定义挂钩 open/close。
自定义挂钩
import { useState, useRef, useEffect } from 'react';
const useCloseOnClickOutside = (initialState) => {
const [isVisible, setIsVisible] = useState(initialState);
const ref = useRef(null);
/**
* Attach Event Listeners
*/
useEffect(() => {
document.addEventListener('click', handleClick, true);
document.addEventListener('touchstart', handleClick, true);
return () => {
document.removeEventListener('click', handleClick, true);
document.removeEventListener('touchstart', handleClick, true);
};
},[]);
const handleClick = (event) => {
if (!ref.current)
return;
// If someone clicks outside the component close the state
if (!ref.current?.contains(event.target)) {
setIsVisible(false);
} else {
// If someone click on the component toggle the state
setIsVisible((prevState => !prevState));
}
};
return {
ref,
isVisible
};
};
export default useCloseOnClickOutside;
下拉菜单
import React from 'react';
import Select from 'react-select';
import useCloseOnClickOutside from '../../hooks/useCloseOnClickOutside';
const Dropdown = ({handleChange, defaultValue, options, value}) => {
const {ref,isVisible} = useCloseOnClickOutside(false);
return (
<div ref={ref}>
<Select
options={options}
onChange={handleChange}
defaultValue={defaultValue}
value={value}
menuIsOpen={isVisible}
/>
</div>
);
};
我将 ref
从 useCloseOnClickOutside
传递到 Select
的外部 div 以捕获气泡事件。
我传递给 Select
onChange
的 handleChange
回调目前什么都不做:
const handleChange = (val) => console.log(val)
并这样称呼它:
父组件
const ParentComponent = () => {
// All theese are just mocked data
const mockedOptions = [];
const handleChange = (val) => console.log(val);
const mockedDefaultValue = 'default-value';
const mockedValue = stateValue;
return (
<Dropdown
handleChange={handleChange}
options={mockedOptions}
defaultValude={mockedDefaultValue}
value={mockedValue}
/>
)
}
问题是,在我将 ref
传递给父 div 的那一刻,onChange
根本没有触发。如果我删除它,它会成功运行。我找不到发生这种情况的任何理由。这可能是 react-select
的问题吗??
我认为你必须在 react-select 触发 onChange
事件后将 menuIsOpen
设置为 false。
看起来如果 select 被隐藏,那么 onChange
事件不会被触发
因此,您可能需要为自定义挂钩添加延迟。然后 select 将在触发 onChange
setTimeout(() => setIsVisible(false));
////
setTimeout(() => setIsVisible((prevState => !prevState)));
PS:我不确定您是否需要自定义挂钩来决定 select 的打开状态,因为这是 react-select[= 的默认行为15=]
我看到问题是您在 addEventListener
中使用了 capture
pharse。所以 setIsVisible(false);
会在 onChange
之前被调用。所以当 select 被隐藏时 onChange
将不会调用。
我看到你有两个解决方案要解决。
删除capture
阶段:
document.addEventListener("click", handleClick);
或延迟 setTimeOut 以确保它在 onChange
:
setTimeout(() => setIsVisible(false), 0);