材质UI,Redux表单和自定义选择

时间:2019-10-21 16:44:14

标签: reactjs redux material-ui redux-form

我正尝试在Redux表单中使用自定义选择,但是无法访问该选择的实际输入。按照MUI网站上的示例,自定义选择如下所示:

import React from 'react';
import deburr from 'lodash/deburr';
import Downshift from 'downshift';
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import TextField, { TextFieldProps } from '@material-ui/core/TextField';

import Paper from '@material-ui/core/Paper';
import MenuItem, { MenuItemProps } from '@material-ui/core/MenuItem';
import Chip from '@material-ui/core/Chip';

interface Suggestion {
  label: string;
}

const suggestions: Suggestion[] = [
  {label: "English"},
  {label: "Music"}
];

type RenderInputProps = TextFieldProps & {
  classes: ReturnType<typeof useStyles>;
  ref?: React.Ref<HTMLDivElement>;
};

function renderInput(inputProps: RenderInputProps) {
  const { InputProps, classes, ref, ...other } = inputProps;

  return (
    <TextField
      InputProps={{
        inputRef: ref,
        classes: {
          root: classes.inputRoot,
          input: classes.inputInput,
        },
        ...InputProps,
      }}

      {...other}
    />
  );
}

interface RenderSuggestionProps {
  highlightedIndex: number | null;
  index: number;
  itemProps: MenuItemProps<'div', { button?: never }>;
  selectedItem: Suggestion['label'];
  suggestion: Suggestion;
}

function renderSuggestion(suggestionProps: RenderSuggestionProps) {
  const { suggestion, index, itemProps, highlightedIndex, selectedItem } = suggestionProps;
  const isHighlighted = highlightedIndex === index;
  const isSelected = (selectedItem || '').indexOf(suggestion.label) > -1;

  return (
    <MenuItem
      {...itemProps}
      key={suggestion.label}
      selected={isHighlighted}
      component="div"
      style={{
        fontWeight: isSelected ? 500 : 400,
      }}
    >
      {suggestion.label}
    </MenuItem>
  );
}

function getSuggestions(value: string, { showEmpty = false } = {}) {
  const inputValue = deburr(value.trim()).toLowerCase();
  const inputLength = inputValue.length;
  let count = 0;

  return inputLength === 0 && !showEmpty
    ? []
    : suggestions.filter(suggestion => {
        const keep =
          count < 5 && suggestion.label.slice(0, inputLength).toLowerCase() === inputValue;

        if (keep) {
          count += 1;
        }

        return keep;
      });
}

interface DownshiftMultipleProps {
  classes: ReturnType<typeof useStyles>;
}

function DownshiftMultiple(props: DownshiftMultipleProps) {
  const { classes } = props;
  const [inputValue, setInputValue] = React.useState('');
  const [selectedItem, setSelectedItem] = React.useState<Array<Suggestion['label']>>([]);

  const handleKeyDown = (event: React.KeyboardEvent) => {
    if (selectedItem.length && !inputValue.length && event.key === 'Backspace') {
      setSelectedItem(selectedItem.slice(0, selectedItem.length - 1));
    }
  };

  const handleInputChange = (event: React.ChangeEvent<{ value: string }>) => {
    setInputValue(event.target.value);
  };

  const handleChange = (item: Suggestion['label']) => {

    let newSelectedItem = [...selectedItem];
    if (newSelectedItem.indexOf(item) === -1) {
      newSelectedItem = [...newSelectedItem, item];
    }
    // this is what needs to be passed back up to the redux form
    setInputValue('');
    setSelectedItem(newSelectedItem);
  };

  const handleDelete = (item: string) => () => {
    const newSelectedItem = [...selectedItem];
    newSelectedItem.splice(newSelectedItem.indexOf(item), 1);
    setSelectedItem(newSelectedItem);
  };

  return (
    <Downshift

      id="downshift-multiple"
      inputValue={inputValue}
      onChange={handleChange}
      selectedItem={selectedItem}
    >
      {({
        getInputProps,
        getItemProps,
        getLabelProps,
        isOpen,
        inputValue: inputValue2,
        selectedItem: selectedItem2,
        highlightedIndex,
      }) => {
        const { onBlur, onChange, onFocus, ...inputProps } = getInputProps({
          onKeyDown: handleKeyDown,
          placeholder: "Select the subjects you'd like to teach",
        });
        return (
          <div className={classes.container}>
            {renderInput({
              fullWidth: true,
              classes,
              label: 'Subjects',
              InputLabelProps: getLabelProps(),
              InputProps: {
                startAdornment: selectedItem.map(item => (
                  <Chip
                    key={item}
                    tabIndex={-1}
                    label={item}
                    className={classes.chip}
                    onDelete={handleDelete(item)}
                  />
                )),
                onBlur,
                onChange: event => {
                  handleInputChange(event);
                  onChange!(event as React.ChangeEvent<HTMLInputElement>);
                },
                onFocus,
              },
              inputProps,

            })}
            {isOpen ? (
              <Paper className={classes.paper} square>
                {getSuggestions(inputValue2!).map((suggestion, index) =>
                  renderSuggestion({
                    suggestion,
                    index,
                    itemProps: getItemProps({ item: suggestion.label }),
                    highlightedIndex,
                    selectedItem: selectedItem2,
                  }),
                )}
              </Paper>
            ) : null}
          </div>
        );
      }}
    </Downshift>
  );
}





export default function CustomSelect() {
  const classes = useStyles({});

  return (
    <div className={classes.root}>
      <DownshiftMultiple 

      classes={classes} />
    </div>
  );
}

我知道Redux Form将输入道具传递给自定义组件,但是我尝试将其放置在导出的Custom Select组件,TextField compoonent和DownshiftMultiple组件中,但是我无法使其正常工作。我希望能够将所选值的数组传递回表单,但是我不确定该怎么做。

如果任何人以前曾遇到过此问题,或者对如何在Redux Form中使用Material UI有所了解,我将非常感谢您的帮助。

非常感谢。

0 个答案:

没有答案