首页 > 解决方案 > 从 SelectBox 中获取值

问题描述

我有一个反应代码

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import SelectBox from '../SelectBox';
import Icon from '../Icon';
import Input from '../Input';
import CountryItem from './components/CountryItem';

const PhoneNumber = props => {
  const { children, className } = props;

  const [selectedOption, setSelectedOption] = useState('');
  const [inputParam, setInputParam] = useState('');

  const inputParamChangeHandler = event => {
    const inputChar = event.target.value;
    setInputParam(inputChar);
    console.log({ inputChar });
  };

  const selectedOptionChangeHandler = event => {
    const valueSelected = event.target.value;
    setSelectedOption(valueSelected);
    console.log({ valueSelected });
  };

  console.log({ children });

  const childrenWithPropsFromParent = React.Children.map(children, child => child);

  const optionsWithImage = [
    {
      value: '+880',
      label: <CountryItem />,
    },
    {
      value: '+55',
      label: (
        <span>
          <span className="phone-number__country-flag">
            <Icon name="home" />
          </span>
          <span>
            <span className="phone-number__country-name">Brazil</span>
            <span className="phone-number__country-code">(+55)</span>
          </span>
        </span>
      ),
    },
    {
      value: '+40',
      label: (
        <span>
          <span className="phone-number__country-flag">
            <Icon name="home" />
          </span>
          <span>
            <span className="phone-number__country-name">Romania</span>
            <span className="phone-number__country-code">(+40)</span>
          </span>
        </span>
      ),
    },
    {
      value: '+44',
      label: (
        <span>
          <span className="phone-number__country-flag">
            <Icon name="home" />
          </span>
          <span>
            <span className="phone-number__country-name">United Kingdom</span>
            <span className="phone-number__country-code">(+44)</span>
          </span>
        </span>
      ),
    },
    {
      value: '+1',
      label: (
        <span>
          <span className="phone-number__country-flag">
            <Icon name="home" />
          </span>
          <span>
            <span className="phone-number__country-name">Bahamas</span>
            <span className="phone-number__country-code">(+1)</span>
          </span>
        </span>
      ),
    },
  ];

  return (
    <div className={classNames('phone-number', className)}>
      <div>Phone Number</div>
      <div className="phone-number__wrapper">
        <SelectBox
          size="small"
          value={selectedOption}
          touched={false}
          onChange={selectedOptionChangeHandler}
          isSearchable={false}
          isDisabled={false}
          isClearable={false}
          options={optionsWithImage}
          width="small"
        />
        <Input value={inputParam} onChange={inputParamChangeHandler} placeholder="XXXX XXX XXX" />
      </div>
      {/* {childrenWithPropsFromParent} */}
    </div>
  );
};

PhoneNumber.defaultProps = {
  children: null,
  className: null,
};

PhoneNumber.propTypes = {
  children: PropTypes.node,
  className: PropTypes.string,
};

export default PhoneNumber;

选择框组件:

import React, { Component } from 'react';
import classnames from 'classnames';
import PropTypes from 'prop-types';
import Select from 'react-select';
import CreatableSelect from 'react-select/creatable';
import './select-box.styles.scss';
import colorOptions from '../../helpers/colorOptions';
import Tooltip from '../Tooltip';
import Icon from '../Icon';

const sizeBasedSelector = (element, size) => {
  switch (size) {
    case 'tiny':
      return `select-box__${element}--tiny`;
    case 'small':
      return `select-box__${element}--small`;
    case 'large':
      return `select-box__${element}--large`;
    default:
      return null;
  }
};

class SelectBox extends Component {
  constructor(props) {
    super(props);
    this.state = {
      selectedOption: props.value,
    };
  }

  customTheme = theme => {
    const { primary, primary75, primary50, primary25 } = this.props.colors;

    return {
      ...theme,
      colors: {
        ...theme.colors,
        primary,
        primary75,
        primary50,
        primary25,
      },
    };
  };

  renderPlaceHolder = () => {
    const { preIcon, placeholderText, size } = this.props;

    return (
      <div className="select-box__placeholder">
        {preIcon && (
          <span className={classnames('select-box__pre-icon', sizeBasedSelector('pre-icon', size))}>
            {preIcon}
          </span>
        )}
        <span
          className={classnames(
            'select-box__placeholder-text',
            sizeBasedSelector('placeholder-text', size)
          )}
        >
          {placeholderText}
        </span>
      </div>
    );
  };

  handleChange = selectedOption => {
    this.setState({ selectedOption });
    this.props.onChange(selectedOption);
  };

  handleInputChange = inputValue => {
    this.props.onInputChange(inputValue);
  };

  getFlags = () => {
    const { isClearable, isDisabled, isMulti, isSearchable } = this.props;
    return {
      isClearable,
      isDisabled,
      isMulti,
      isSearchable,
    };
  };

  render() {
    const { selectedOption } = this.state;
    const {
      autoFocus,
      className,
      classNamePrefix,
      colors,
      errorMsg,
      label,
      name,
      options,
      size,
      touched,
      isMulti,
      isDisabled,
      isCreatable,
      width,
      required,
    } = this.props;
    const hasError = touched && errorMsg;
    const selectProps = {
      ...this.getFlags(),
      autoFocus,
      className: classnames(
        `${className} ${className}--${size}`,
        sizeBasedSelector('width', width),
        {
          'select-box-container--notMulti': !isMulti,
          'select-box-container--error': hasError,
        }
      ),
      classNamePrefix,
      colors,
      theme: this.customTheme,
      value: selectedOption,
      name,
      options,
      onInputChange: this.handleInputChange,
      onChange: this.handleChange,
      placeholder: this.renderPlaceHolder(),
      required,
    };

    return (
      <>
        {label && (
          <span
            className={classnames(`select-box__label select-box__label--${size}`, {
              'select-box__label--required': required,
              'select-box__label--disabled': isDisabled,
            })}
          >
            {label}
          </span>
        )}
        <div className="select-box-wrapper">
          {isCreatable ? <CreatableSelect {...selectProps} /> : <Select {...selectProps} />}
          {errorMsg && (
            <Tooltip
              classNameForWrapper="select-box__tooltip-wrapper"
              classNameForTooltip="select-box__tooltip"
              content={errorMsg}
              position="bottom-right"
              gap={0}
            >
              <Icon name="invalid" />
            </Tooltip>
          )}
        </div>
      </>
    );
  }
}

SelectBox.defaultProps = {
  autoFocus: false,
  className: 'select-box-container',
  classNamePrefix: 'select-box',
  colors: {
    primary: colorOptions.coolGray20,
    primary75: colorOptions.coolGray45,
    primary50: colorOptions.coolGray70,
    primary25: colorOptions.coolGray95,
  },
  errorMsg: '',
  isClearable: true,
  isCreatable: false,
  isDisabled: false,
  isMulti: false,
  isSearchable: true,
  label: '',
  name: 'select-box',
  onChange: () => {},
  onInputChange: () => {},
  options: [],
  placeholderText: 'Select...',
  preIcon: null,
  required: false,
  size: 'small',
  touched: false,
  value: null,
  width: 'small',
};

SelectBox.propTypes = {
  autoFocus: PropTypes.bool,
  className: PropTypes.string,
  classNamePrefix: PropTypes.string,
  colors: PropTypes.shape({
    primary: PropTypes.string,
    primary75: PropTypes.string,
    primary50: PropTypes.string,
    primary25: PropTypes.string,
  }),
  errorMsg: PropTypes.string,
  isClearable: PropTypes.bool,
  isCreatable: PropTypes.bool,
  isDisabled: PropTypes.bool,
  isMulti: PropTypes.bool,
  isSearchable: PropTypes.bool,
  label: PropTypes.string,
  name: PropTypes.string,
  onChange: PropTypes.func,
  onInputChange: PropTypes.func,
  options: PropTypes.arrayOf(
    PropTypes.shape({
      label: PropTypes.string,
      value: PropTypes.string,
    })
  ),
  preIcon: PropTypes.node,
  placeholderText: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
  value: PropTypes.oneOf([
    PropTypes.shape({
      label: PropTypes.string,
      value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
    }),
    PropTypes.arrayOf(
      PropTypes.shape({
        label: PropTypes.string,
        value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
      })
    ),
  ]),
  required: PropTypes.bool,
  size: PropTypes.oneOf(['tiny', 'small', 'large']),
  touched: PropTypes.bool,
  width: PropTypes.oneOf(['tiny', 'small', 'large', 'full']),
};

export default SelectBox;

现在我想selectedOptionSelectBox组件中获取 的值,但是当我从SelectBox. 错误是

Uncaught TypeError: Cannot read property 'value' of undefined
    at Object.selectedOptionChangeHandler [as onChange] (PhoneNumber.jsx:22)
    at Object.onChange (SelectBox.jsx:71)
    at StateManager.callProp (stateManager-04f734a2.browser.esm.js:98)
    at StateManager._this.onChange (stateManager-04f734a2.browser.esm.js:38)
    at Select._this.onChange (Select-9fdb8cd0.browser.esm.js:1079)
    at Select._this.setValue (Select-9fdb8cd0.browser.esm.js:1106)
    at Select._this.selectOption (Select-9fdb8cd0.browser.esm.js:1155)
    at onSelect (Select-9fdb8cd0.browser.esm.js:1732)
    at HTMLUnknownElement.callCallback (react-dom.development.js:336)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:385)

如何从SelectBox使用当前实现的 onChange 中获取值?

标签: javascriptreactjsselect

解决方案


您的SelectBox组件的handleChange回调输出所选值与事件,因此您应该使用该值。

选择框

handleChange = selectedOption => {
  this.setState({ selectedOption });
  this.props.onChange(selectedOption); // <-- sends selected value!
};

电话号码

const selectedOptionChangeHandler = valueSelected => { // <-- consume valueSelected
  setSelectedOption(valueSelected);
  console.log({ valueSelected });
};

推荐阅读