多选作为按钮组

Multiselect as a Button Group

我一直在努力寻找 redux 形式的具有多个值的字段的最佳实践。

这就是我想要完成的。

那些按钮是自定义组件。我让它在视觉上工作,使用自定义组件和 onChange 来更新隐藏复选框字段的 redux 值。

这似乎是一个相当常见的用例,因为它本质上是一个多选。我知道文档 roccomend 使用 react-widgets multiselect 但它似乎不适合我试图完成的按钮组样式。这是我到目前为止所拥有的,但是将 redux-form 视图复选框视为布尔值而不是数组,我认为这对我不起作用。

import React, {Component} from 'react'
import {Field} from 'redux-form'
import * as icons from './../MultiSelectBtnGrid/icons'

const btnStyles = {
  border: '3px solid #f6e9db',
  background: 'transparent',
  borderRadius: '45px',
  width: '250px'
}

const btnSelectedStyles = {
  border: '3px solid #27313c',
  background: 'transparent',
  borderRadius: '45px',
  width: '250px'
}

class MultiSelectField extends Component {
  constructor(props) {
    super(props)
    this.state = {selected: false}
    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState({selected: !this.state.selected})
    this.props.input.onChange(!this.state.selected)
  }

  render() {
    const {content, idx, input: {name}} = this.props
    const {selected} = this.state
    return (
      <div className={'row m-auto rel'}>
        <button type={'button'} className={`mb-1 p-3 ml-auto mr-auto`} style={selected ? btnSelectedStyles : btnStyles}
                onClick={this.handleClick}>
          {content}
          <span style={{position: 'absolute', right: '15px', top: '0', bottom: '0', margin: 'auto'}}
                className={'mb-1 d-flex justify-content-center align-items-center'}>{icons.plusIcon(selected)}</span>
        </button>
        <input type={'checkbox'} name={`${name}`} value={selected ? 'test' : null} checked={selected} />
      </div>
    )
  }
}

export default class MultiSelectBtnGroup extends Component {
  constructor(props) {
    super(props)
    this.state = {selected: props.formState.values[props.name]}
  }

  render() {
    const {options, name} = this.props
    return (
      <div className={'container'}>
        <div className={'row'}>
          {options.map((option, idx) => {
            return <Field
              component={MultiSelectField}
              name={name}
              type='checkbox'
              content={option.content}
              key={idx}
              {...this.props}
              className={'col'}
              idx={idx}/>
          })}
        </div>
      </div>
    )
  }
}

MultiSelectBtnGroup 应该是 Field 的组件,使值成为表单状态中的数组。

这是一个例子:

const MultiSelectBtnGroup = { input, options } => {
    const values = input.value || [];

    const handleClick = (value, select) => {
        var index = values.indexOf(value);

        if (select) {
            if (index === -1) {
                input.onChange([...values, value]);
            }
        } else {
            if (index !== -1) {
                input.onChange(values.filter(v => v !== value));
            }
        }
    };

    return (
        <div className="row">
            {options.map(o => {
                const selected = values.indexOf(o.value) !== -1;
                return (
                    <div className="col">
                        <div className="row m-auto rel">
                            <button
                                type="button"
                                className="mb-1 p-3 ml-auto mr-auto"
                                style={selected ? btnSelectedStyles : btnStyles}
                                onClick={e => handleClick(o.value, !selected)}
                            >
                                {o.content}
                                <span
                                    style={{ position: 'absolute', right: '15px', top: 0, bottom: 0, margin: 'auto' }}
                                    className="mb-1 d-flex justify-content-center align-items-center"
                                >
                                    {icons.plusIcon(selected)}
                                </span>
                            </button>

                            <input
                                type="hidden"
                                name={name}
                                value={o.value}
                                checked={selected}
                            />
                        </div>
                    </div>
                );
            })}
        </div>
    );
};

const Example = { options, name } => (
    <div className="container">
        <Field component={MultiSelectField} name={name} />
    </div>
);

<input> 不需要在那里维护表单状态,但如果您想以传统方式提交表单,它会很有帮助。