Home > Enterprise >  I used two 'setState' inside a handleChange of input, for searching on the array. why the
I used two 'setState' inside a handleChange of input, for searching on the array. why the

Time:12-14

I have an array of the names of cities. also, I have an input that I want the any input value to be searched on the array, and synchronously show the input's placeholder according to city's name that started with input value, whenever that user typing a character.

a part of cities.json:

[ "Aberdeen", "Abilene", "Akron", "Albany", "Albuquerque", "Alexandria", "Allentown", "Amarillo", "Anaheim", "Anchorage", "Ann Arbor", "Antioch", "Apple Valley", "Appleton", "Arlington", "Arvada", "Asheville", "Athens", "Atlanta", "Atlantic City", "Augusta", "Aurora", "Austin", "Bakersfield", "Baltimore", "Barnstable", "Baton Rouge", "Beaumont", . . . . . . . . . . . . . . . "Wilmington", "Winston", "Winter Haven", "Worcester", "Yakima", "Yonkers", "York", "Youngstown" ]

index.jsx:

import React from "react";
import ReactDOM from "react-dom";
import cities from "./cities.json"; //cities is an array.

class App extends React.Component{
    constructor(props) {
        super(props);
        this.state = {
            value: '',
            placeholder: ''
        }
    }

    handleChange = (e) => {
        this.setState({
            value: e.target.value
        });
        for (let i = 0; i < cities.length; i  ){
            if (cities[i].startsWith(`${this.state.value}`)){
                this.setState({
                    placeholder: cities[i]
                });
            }
        }
    }


    render() {
        return (
            <div>
                <input value={this.state.value} placeholder={this.state.placeholder} onChange={this.handleChange}/>
            </div>
        );
    }
}

ReactDOM.render(<App/>, document.getElementById("root"));

But two issues:

1- Use two setState: Do second setState use result of first setState?

2- Output is not expected: typed value is not synchronous with placeholder value. placeholder is shown when the input is cleared(while the placeholder must be empty,too). also it only shows first city, with any starter letter. e.g if I type "Akro" or "Alba", it shows "Aberdeen" instead "Akron" and "Albany", as placeholder. as well as if I type "Baton", it shows "Bakersfield" instead "Baton Rouge"(note the array).

my output:

enter image description here enter image description here

expected output:

enter image description here

What is your solution? :)

CodePudding user response:

the setState function is async, so if you want to use the newly state you have to provide a callback to setState and use the new state inside it. So, for example, in your case you have to do something like:

handleChange = (e) => {
      this.setState({
          value: e.target.value
      }, () => {

        for (let i = 0; i < cities.length; i  ){
            if (cities[i].startsWith(`${this.state.value}`)){
                this.setState({
                    placeholder: cities[i]
                });
            }
        }
      });
  }

CodePudding user response:

@Marco Nisi is correct but according to your question you want the saw city suggestions. @Arman placeholder is only displayed when there is no value in the input box. but you can use the datalist provided in the html. Please find the link to the working solution here.

import React from "react";
import cities from "./cities.json"; //cities is an array.

class App extends React.Component {
constructor(props) {
    super(props);
    this.state = {
    value: "",
    placeholder: "",
    suggestions: []
    };
}

handleChange = (e) => {
    // saving current input value to state
    this.setState(
    {
        value: e.target.value
    },
    () => {
        // empty the suggestions array state to remove previous suggestions
        this.setState({
        suggestions: []
        });
        for (let i = 0; i < cities.length; i  ) {
        if (cities[i].startsWith(`${this.state.value}`)) {
            this.setState(
            {
                suggestions: [...this.state.suggestions, cities[i]]
            });
        }
        }
    }
    );
};

render() {
    return (
    <div>
        <label htmlFor="city">Choose your city:</label>
        <input
        value={this.state.value}
        placeholder={this.state.placeholder}
        onChange={this.handleChange}
        list="suggested_cities"
        name="city"
        id="city"
        />
        <datalist id="suggested_cities">
        {this.state.suggestions.map((suggestion) => {
            return <option value={suggestion} key={suggestion} />;
        })}
        </datalist>
    </div>
    );
}
}

export default App;

Link to the fiddle for working example. https://codesandbox.io/s/react-fiddle-forked-viqmt?from-embed

  • Related