2
votes

I have a class component which renders an input and a tooltip and controls state. The <SelectInputType> components job is to take a single prop of 'type' and render either a text input, a textarea, a select input or a checkbox group component. There are a load of props that need to be passed through this SelectInputType component, some of which are relevant to all 4 of the input components (placeholderText and required for example) and some of which are specific to a particular input (options for example is only relevant to checkboxes and select inputs).

render() {
    const inputProps = {};
    inputProps.placeholderText = this.props.placeholderText;
    inputProps.required = this.props.required;
    inputProps.class = this.props.class;
    inputProps.value = this.props.value;
    inputProps.options = this.props.options;
    inputProps.updateText = this.handleInput;
    inputProps.handleFocus = this.focusIn;
    inputProps.handleBlur = this.focusOut;
    inputProps.handleCheckboxChange = e => this.addCheckboxToList(e);
    inputProps.closeCheckboxSelector = this.closeCheckboxSelector;
    inputProps.readableSelectedCheckboxes = this.state.readableSelectedCheckboxes;

    const inputClass = classNames('input-with-tooltip', {
      focus: this.state.focus,
      'step-complete': this.state.completed,
    });

    return (
      <div className={inputClass}>
        <InputTooltip
          tooltipText={this.props.tooltipText}
          completed={this.state.completed}
        />
        <div className="drill-creation-input">
          <SelectInputType type={this.props.type} {...inputProps} />
        </div>
      </div>
    );
  }

My SelectInputType component looks like this...

const SelectInputType = (props) => {
  let component;
  if (props.type === 'title') {
    component = <TextInput />;
  } else if (props.type === 'text') {
    component = <TextareaInput />;
  } else if (props.type === 'checkbox') {
    component = <CheckboxInput />;
  } else if (props.type === 'select') {
    component = <SelectInput />;
  }

  return (
    <div>
      {component}
      // Need to pass props through to this?
    </div>
  );
};

I am using the JSX spread attribute to pass the props down to the SelectInputType component, but I don't know how to then pass these on to the 4 input components (and if I do pass them on will I have errors with certain props not being valid on particular components?)

2

2 Answers

2
votes

You could alternatively save the component type in the variable, not the component itself:

const SelectInputType = (props) => {
  let ComponentType;
  if (props.type === 'title') {
    ComponentType = TextInput;
  } else if (props.type === 'text') {
    ComponentType = TextareaInput;
  } else if (props.type === 'checkbox') {
    ComponentType = CheckboxInput;
  } else if (props.type === 'select') {
    ComponentType = SelectInput;
  }

  return (
    <div>
      <ComponentType {..props} />
    </div>
  );
};
1
votes

You might get errors. If so you could create utility functions to extract the props you need per input type:

extractTextInputProps(props) {
    const { value, className, required } = props
    return { value, className, required }
}

extractSelectInputProps(props) {
    const { value, handleBlur, updateText } = props
    return { value, handleBlur, updateText }
}

You could probably extract a more generic function out of this so you don't have to repeat the property name twice.

Then use them when creating your components with the spread operator:

let component;
if (props.type === 'title') {
    component = <TextInput { ...extractTextInputProps(props) } />;
} else if (props.type === 'text') {
    component = <TextareaInput />;
} else if (props.type === 'checkbox') {
    component = <CheckboxInput />;
} else if (props.type === 'select') {
    component = <SelectInput { ...extractSelectInputProps(props) } />;
}