profile
viewpoint

Ask questionsSwitching between controlled and uncontrolled input

I have set up an autocomplete with downshift and it works perfectly... except it gives me the following warning whenever i select an option.

Warning: A component is changing a controlled input of type text to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component

As far as i can tell (by looking at what i set the value to before and after the selection) I am not changing the input to undefined or null (what most commonly causes this issue).

My downshift version is 1.31.16 My node version is 9.2.1 My npm version is 5.10.0 My material ui version is 1.2.3

My code is as follows

import React from 'react';
import PropTypes from 'prop-types';
import Downshift from 'downshift';
import TextField from '@material-ui/core/TextField';
import Paper from '@material-ui/core/Paper';
import Avatar from '@material-ui/core/Avatar';
import MenuItem from '@material-ui/core/MenuItem';
import ListItemText from '@material-ui/core/ListItemText';

export class Autocomplete extends React.PureComponent {
  static propTypes = {
    items: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
    onSelect: PropTypes.func.isRequired,
    onChange: PropTypes.func.isRequired,
    value: PropTypes.string,
    inputDetails: PropTypes.shape({}).isRequired,
    disconect: PropTypes.bool,
  };

  static defaultProps = {
    value: '',
    disconect: false,
  }

  getSuggestions = (items, inputValue, disconect) => {
    if(disconect){return []}
    return items.filter(suggestion => {
      const keep = !inputValue ||
                    (suggestion.primary || '').toLowerCase().match(inputValue.toLowerCase()) ||
                    (suggestion.secondary && suggestion.secondary.toLowerCase().match(inputValue.toLowerCase()));

      return keep;
    });
  }

  render() {
    const { onSelect, onChange, value, items, inputDetails, disconect } = this.props;
    return (
      <Downshift
        style={{position: 'relative'}}
        onChange={(selection, functions) => onSelect(selection, functions)}
        onStateChange={({inputValue, type}) => {
          if(type === '__autocomplete_change_input__' || type === '__autocomplete_click_item__'){
            onChange((inputValue || ''));
          }
        }}
        itemToString={(item) => { return item ? item.primary : ''}}
        render={({
          getInputProps,
          getItemProps,
          getLabelProps,
          isOpen,
          inputValue,
          highlightedIndex,
          selectedItem,
          clearSelection,
        }) => (
          <div>
            <TextField
              InputProps={{
                ...getInputProps(),
                placeholder: inputDetails.placeholder,
                name: inputDetails.name,
                id: inputDetails.id,
                value,
              }}
              label={inputDetails.label}
              fullWidth={inputDetails.fullWidth}
            />
            {isOpen &&
              <Paper style={{
                position: 'absolute',
                zIndex: 1,
              }}>
                {
                  this.getSuggestions(items, inputValue, disconect)
                  .map((item, index) => (
                    <MenuItem
                      {...getItemProps({
                        item: item,
                      })}
                      key={item._id}
                      style={{ height: 50 }}
                    >
                      {inputDetails.avitar &&
                        <Avatar>{item.primary[0]}</Avatar>
                      }
                      <ListItemText
                        primary={item.primary}
                        secondary={item.secondary}
                      />
                    </MenuItem>
                  ))
                }
              </Paper>
            }
          </div>
        )}
      />
     );
   }
}

export default (Autocomplete);

Reproducing Bug To reproduce i type into the autofill field created and select an option from the suggestions that come up.

when a suggestion is selected it creates a warning that I am changing from a controlled to uncontrolled input.

downshift-js/downshift

Answer questions paulisloud

I was experiencing this issue as well. Solved it by setting value on the input:

<input
  {...getInputProps({
    type: "search",
    placeholder: "Search",
    id: "search",
    name: "search",
    className: loading ? "loading" : "",
    value: props.value,
    onChange: e => {
      e.persist();
      onChange(e, hits, refine);
    }
  })}
/>
useful!

Related questions

TypeScript compiler error with ref passed from getInputProps to component using a forwardRef hot 2
Double rendering (Lifecycle hook scheduled a cascading update) after item selection hot 1
TypeScript: definitions missing `preventDownshiftDefault` hot 1
Errors "You returned a non-DOM element. You must specify a refKey in getRootProps" hot 1
Support RefObjects for sub-components hot 1
Apollo with debounce example - downshift hot 1
source:https://uonfu.com/
Github User Rank List