3

I am trying to display a new text input based on the selected option. I am able to do that as below but the old value entered is always present no matter what I change the new select option to.

What might be a better way to achieve this? Appreciate any suggestions.

class loadComponent extends React.Component {
    static propTypes = {
      ......
    };
    static defaultProps = {
     ....
    };
    constructor() {
     super();
     this.state = {
       value: ""
     };
    }
     state = {
      ...
     };

reset = (selected) => {
       this.setState({
        selectedInputName: selected.target[selected.target.selectedIndex].text,
        selectedInputId: selected.target.value
       });
};

makeTextInput = () => {
    return (
        <TextInput
            label={this.state.selectedInputName}
            placeholder={`Please enter ${this.state.selectedInputName} here!`}
            onBlur={event => this.setState({[this.state.selectedInputId]: event.target.value})}
            showClear
            value={this.state.value}
        />
    );
};
render() {
    let newInputText = '';
    if (this.state.selectedInputId !== '') {
        newInputText = this.makeTextInput();
    }
    return (
        <Select
            label="What would you like to search with?"
            options={this.props.searchOptions}
            onChange={selected => this.reset(selected)}
        />
        <div className="search margin_bottom_large">
            {newInputText}
    );
3
  • so basically you want to clear the current input from the user when the input type is changed? Commented Aug 14, 2017 at 15:19
  • @canaanseaton Yeah, Thats exactly what I am trying to achieve. Commented Aug 14, 2017 at 15:30
  • okay, see my solution below. Doing something of that sort will allow you to reset the value of the input anytime you want, say when an input type changes. Commented Aug 14, 2017 at 15:31

3 Answers 3

3

makeTextInput function creates a new object, but from react's perspective it's the same component because react distinguishes them by looking at their type and key. To make react recreate an element, you have to change one of those values.

This code changes type of NewInputText element each time it renders (because NewInputText always refers to a new function):

reset = (selected) => {
       this.setState({
        selectedInputName: selected.target[selected.target.selectedIndex].text,
        selectedInputId: selected.target.value
       });
};

makeTextInput = () => {
    return (
        <TextInput
            label={this.state.selectedInputName}
            placeholder={`Please enter ${this.state.selectedInputName} here!`}
            onBlur={event => this.setState({[this.state.selectedInputId]: event.target.value})}
            showClear
        />
    );
};
render() {
    let NewInputText = () => '';
    if (this.state.selectedInputId !== '') {
        NewInputText = () => this.makeTextInput();
    }
    return (
        <Select
            label="What would you like to search with?"
            options={this.props.searchOptions}
            onChange={selected => this.reset(selected)}
        />
        <div className="search margin_bottom_large">
            <NewInputText />
    );

This code assigns different key to TextInput each time:

reset = (selected) => {
       this.setState({
        selectedInputName: selected.target[selected.target.selectedIndex].text,
        selectedInputId: selected.target.value
       });
};

makeTextInput = () => {
    return (
        <TextInput
            key={Math.random()}
            label={this.state.selectedInputName}
            placeholder={`Please enter ${this.state.selectedInputName} here!`}
            onBlur={event => this.setState({[this.state.selectedInputId]: event.target.value})}
            showClear
        />
    );
};
render() {
    let newInputText = '';
    if (this.state.selectedInputId !== '') {
        newInputText = this.makeTextInput();
    }
    return (
        <Select
            label="What would you like to search with?"
            options={this.props.searchOptions}
            onChange={selected => this.reset(selected)}
        />
        <div className="search margin_bottom_large">
            {newInputText}
    );
Sign up to request clarification or add additional context in comments.

2 Comments

Awesome!! You brought all my struggles to an end. Thank you for the detailed explanation.
How can I do this in a functional component ?
2

Is there a better way to do this?

I think using the controlled component design pattern would be ideal in this situation.

class SomeInput extends Component {
    constructor() {
        super();

        this.state = {
            value: "" //Keep value state here
        };
    }

    render() {
        /* Doing something like the following will allow you to clear
           the input value simply by doing the following..

           this.setState({ value: '' });
        */
        return (
            <Input
                type="text"
                onChange={e => this.setState({ value: e.target.value })} // set value state to entered text
                value={this.state.value} // set value of input to value piece of state
            />
        );
    }
}

This will give you full access to the current value of the input, thereby allowing you to set it to anything or clear it at anytime or for any event simply by doing the following this.setState({ value: '' }).

3 Comments

It won't render when I use a constructor. Not sure why. I am not using form here too. Should controlled component always use form?
nope, form doesnt matter, its just dictates the method for controlling value being captured in the component state and being rendered back through using the value on an input.
can you post your code with a constructor so i can see what might be going on
0

Don't know the rest of your code which could be handy but you can try:

makeTextInput = () => (
        <TextInput
          label={this.state.selectedInputName}
          placeholder={`Please enter ${this.state.selectedInputName} here!`}
          onBlur={event => this.setState({[this.state.selectedInputId]: event.target.value})}
          showClear
        />
      );

change = (event) => {
     this.setState({
       selectedInputName: event.target.value
     });
 }   

render() {
      return (
          <Select
            label="What would you like to search with?"
            options={this.props.searchOptions}
            onChange={this.change}
          />
          <div className="search margin_bottom_large">
          {this.makeTextInput()}
       );

What you need to do is only setState properly. Each time you change a state the component will be re-rendered which means that the makeTextInput method will be triggered.

EDIT:

by the way, it is good idea to use getter for returning component in render method, in this case:

get textInput() { 
    return (
       <TextInput
         label={this.state.selectedInputName}
         placeholder={`Please enter ${this.state.selectedInputName} here!`}
         onBlur={event => this.setState({[this.state.selectedInputId]: event.target.value})}
         showClear
       />
    );

}

and then in render method, just use {this.textInput}

1 Comment

I updated the code above. I am doing what you mentioned. I am able to change the label. My problem was that the input value which was previously entered is always being present even if the selected option is changed. I am trying to reset that somehow. but I have had no luck so far.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.