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>
  );
};

我将 refuseCloseOnClickOutside 传递到 Select 的外部 div 以捕获气泡事件。

我传递给 Select onChangehandleChange 回调目前什么都不做:

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);