使用 redux-form 和 react-select.creatable 为啥模糊事件会清除输入?

Posted

技术标签:

【中文标题】使用 redux-form 和 react-select.creatable 为啥模糊事件会清除输入?【英文标题】:with redux-form and react-select.creatable why does a blur event clear the input?使用 redux-form 和 react-select.creatable 为什么模糊事件会清除输入? 【发布时间】:2018-08-04 16:48:55 【问题描述】:

我正在使用:

反应 15.6.2 redux-form 7.2.0 反应选择 1.2.1

我还没有为此设置代码笔,这很复杂。希望有人会单独从源头上看到问题。我可以做梦,不是吗?

我有一个 redux-form 显示一个 invoice 对象:

invoice =  client:  email: 'someguy@somewhere.com'  

总结:我使用react-select.creatable 作为电子邮件下拉列表的自动完成组件。选择email 会在invoice 上设置client

当我创建一个新的电子邮件地址并选择它,然后模糊输入字段时,输入值被清除。

invoice 表单上的新 client 仍然在 redux 存储中正确设置,它只是从字段的输入值中清除。为什么?

请注意,根据其他答案,我已经使用正确的值从 Select 手动调用 input.onBlur()。我认为这与创建新选项有关。

// 包装自定义自动完成组件的 redux-form 字段

const clientOptions = clients.map(client => ( label: client.email, value: client )) const isValidNewOption = ( label ) => email.REG_EMAIL.test(label) const promptTextCreator = (label) => (Send to $label) const newOptionCreator = (label, labelKey, valueKey) => 返回标签:标签,值:电子邮件:标签

// RFReactSelect,一个react-select 可创建作为自动完成功能,能够创建一个新选项

import React,  PropTypes  from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';

RFReactSelect.defaultProps = 
  multi: false,
  className: ""
;

RFReactSelect.propTypes = 
  input: PropTypes.shape(
    name: PropTypes.string.isRequired,

    onBlur: PropTypes.func.isRequired,
    onChange: PropTypes.func.isRequired,
    onFocus: PropTypes.func.isRequired,
  ).isRequired,
  options: PropTypes.array.isRequired,
  multi: PropTypes.bool,
  className: PropTypes.string,
  onNewOptionClick: PropTypes.func,
;

export default function RFReactSelect(props) 
  const  input , options, multi, className,
    newOptionCreator, promptTextCreator, isValidNewOption  = props
  const  name, value, onBlur, onChange, onFocus  = input;
  const transformedValue = transformValue(value, options, multi);

  return (
    <Select.Creatable
      className=className
      isValidNewOption=isValidNewOption
      name=name
      multi=multi
      newOptionCreator=newOptionCreator
      onSelectResetsInput=false
      onBlurResetsInput=false
      options=options
      onChange=multi
        ? multiChangeHandler(onChange)
        : singleChangeHandler(onChange)
      
      onBlur=() => onBlur(value)
      onFocus=onFocus
      promptTextCreator=promptTextCreator
      value=transformedValue
      valueKey='value'
    />
  );


/**
 * onChange from Redux Form Field has to be called explicity.
 */
function singleChangeHandler(func) 
  return function handleSingleChange(value) 
    func(value ? value.value : '');
  ;


/**
 * onBlur from Redux Form Field has to be called explicity.
 */
function multiChangeHandler(func) 
  return function handleMultiHandler(values) 
    func(values.map(value => value.value));
  ;


/**
 * For single select, Redux Form keeps the value as a string, while React Select
 * wants the value in the form  value: "grape", label: "Grape" 
 *
 * * For multi select, Redux Form keeps the value as array of strings, while React Select
 * wants the array of values in the form [ value: "grape", label: "Grape" ]
 */
function transformValue(value, options, multi) 
  if (multi && typeof value === 'string') return [];

  const filteredOptions = options.filter(option => 
    return multi
      ? value.indexOf(option.value) !== -1
      : option.value === value;
  );

  return multi ? filteredOptions : filteredOptions[0];

【问题讨论】:

【参考方案1】:

我解决了。问题是您必须跟踪本地状态下新创建的选项,并将它们与组件的props.options 连接起来,否则新选项在重新渲染时会丢失。所以value 传回FieldonBlur 为空。这是来源:

import React,  Component, PropTypes  from 'react';
import Select from 'react-select';
import 'react-select/dist/react-select.css';

class RFReactSelect extends Component 
  constructor() 
    super()

    this.state = 
      createdOptions: []
    

    this.onNewOptionClick = this.onNewOptionClick.bind(this)
  

  render() 
    const  input , options, multi, className,
      newOptionCreator, promptTextCreator, isValidNewOption  = this.props
    const  name, value, onBlur, onChange, onFocus  = input;
    const allOptions = options.concat(this.state.createdOptions)
    const transformedValue = this.transformValue(value, allOptions, multi);

    return (
      <Select.Creatable
        className=className
        isValidNewOption=isValidNewOption
        multi=multi
        name=name
        newOptionCreator=newOptionCreator
        onSelectResetsInput=false
        onBlurResetsInput=false
        options=allOptions
        onChange=multi
          ? this.multiChangeHandler(onChange)
          : this.singleChangeHandler(onChange)
        
        onBlur=() => onBlur(value)
        onFocus=onFocus
        onNewOptionClick=this.onNewOptionClick
        promptTextCreator=promptTextCreator
        ref='creatable'
        value=transformedValue
        valueKey='value'
      />
    );
  

  /**
   * Keep created options in local state or they will be lost
   * on re-render
   */
  onNewOptionClick(option) 
    const  props, select  = this.refs.creatable
    const  options  = props

    options.unshift(option)
    select.selectValue(option)

    this.setState(
      createdOptions: [option]
    )
  

  /**
   * onChange from Redux Form Field has to be called explicity.
   */
  singleChangeHandler(func) 
    return function handleSingleChange(option) 
      func(option ? option.value : '');
    ;
  

  /**
   * onBlur from Redux Form Field has to be called explicity.
   */
  multiChangeHandler(func) 
    return function handleMultiHandler(values) 
      func(values.map(value => value.value));
    ;
  

  /**
   * For single select, Redux Form keeps the value as a string, while React Select
   * wants the value in the form  value: "grape", label: "Grape" 
   *
   * * For multi select, Redux Form keeps the value as array of strings, while React Select
   * wants the array of values in the form [ value: "grape", label: "Grape" ]
   */
  transformValue(value, options, multi) 
    if (multi && typeof value === 'string') return [];

    const filteredOptions = options.filter(option => 
      return multi
        ? value.indexOf(option.value) !== -1
        : option.value === value;
    );

    return multi ? filteredOptions : filteredOptions[0];
  


RFReactSelect.defaultProps = 
  multi: false,
  className: ""
;

RFReactSelect.propTypes = 
  input: PropTypes.shape(
    name: PropTypes.string.isRequired,
    onBlur: PropTypes.func.isRequired,
    onChange: PropTypes.func.isRequired,
    onFocus: PropTypes.func.isRequired,
  ).isRequired,
  options: PropTypes.array.isRequired,
  multi: PropTypes.bool,
  className: PropTypes.string,
  onNewOptionClick: PropTypes.func,


export default RFReactSelect

【讨论】:

你能为这个例子创建一个沙箱吗?

以上是关于使用 redux-form 和 react-select.creatable 为啥模糊事件会清除输入?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Redux-Form 的值返回 null

使用 React-intl 的 Redux-form 字段级验证和错误翻译

使用 axios 和 redux-thunk 以 redux-form 发布请求

如何使用 redux-form 在不同组件(向上一个组件)中显示 FieldArray 中的字段

react.js:使用 redux-form、rest api 和 async/await 创建资源

如何通过重新选择使用 redux-form