Ad

Render List Of Elements Based On User's Input

- 1 answer

Context I'm new to React and so I'm building basic form where I would like to display a list of countries based on the user's input. My app is made up of two components: Filter (this is the input field where the user will enter their input) and Display (this will display the countries that meet the user's input

So far, I've been able to log the user's input to the console. However, inside the useEffect() hook, when I add in a line to update the countries state array to the user's input, nothing happens. How can I update the countries array with the user's input?

CodeApp.js

import React, {useEffect, useState} from 'react'
import axios from 'axios'
import Filter from './components/Filter'
import Display from './components/Display'


function App() {
  const [countries, setCountries] = useState(['france', 'spain', 'germany', 'greece', 'portugal'])
  const [searchTerms, setSearchTerms] = useState('')
  const handleSearchInput = (event) => setSearchTerms(event.target.value)


  useEffect(() => {
   let results = countries.filter(country => country === searchTerms)
      console.log("results: ", results)
      setSearchTerms(searchTerms)
      setCountries(results)
  }, [])


  return (
    <div>
      <h1>Countries</h1>
      <Filter value={searchTerms} handleChange={handleSearchInput}/>
      <Display filteredArr={countries}/>
    </div>
  );
}

export default App;

Display

import React from 'react'

export default function Display({filteredArr, arr}){ 
    return(
        <p>
            {filteredArr.map(country => <div>{country}</div>)}
        </p>
    )
}

Filter component

export default function Filter({searchResult, handleChange}){
    return(
        <div>
            <input value={searchResult} onChange={handleChange} placeholder='Search for countries'/>
        </div>
    )
}
Ad

Answer

Since the effect hook has an empty dependency array, it runs only on mount - and on mount, the searchTerms string is empty, so the results array will also be empty.

Don't use the effect hook - instead, have the handleSearchInput filter and set state. You'll also need a persistent list of countries - if you filter and set the state of the countries, and the user input changes again, you'll want to subsequently filter the original list of countries, not the already-filtered list of countries.

function App() {
  const initialCountries = ['france', 'spain', 'germany', 'greece', 'portugal'];
  const [countries, setCountries] = React.useState(initialCountries)
  const [searchTerms, setSearchTerms] = React.useState('')
  const handleSearchInput = (event) => {
    setSearchTerms(event.target.value);
    setCountries(
      initialCountries.filter(
        country => country === event.target.value
      )
    );
  };
  return (
    <div>
      <h1>Countries</h1>
      <Filter value={searchTerms} handleChange={handleSearchInput}/>
      <Display filteredArr={countries}/>
    </div>
  );
}

function Display({filteredArr, arr}){ 
    return(
        <p>
            {filteredArr.map(country => <div>{country}</div>)}
        </p>
    )
}
function Filter({searchResult, handleChange}){
    return(
        <div>
            <input value={searchResult} onChange={handleChange} placeholder='Search for countries'/>
        </div>
    )
}

ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/[email protected]/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/[email protected]/umd/react-dom.development.js"></script>
<div class='react'></div>

Your current logic seems a bit odd though - do you really want to only show countries that exactly match the input? I'm not sure what you're trying to achieve here, but if you only want exact matches, it might be more user-friendly to make the countries clickable to toggle them, rather than using a text input. If you want to show multiple countries that contain the same user input substring, use .includes instead of === in the filter test.

You also might want to display all countries again if the input is empty, in which case you'd do:

setCountries(
  event.target.value === '' ? initialCountries : initialCountries.filter(
    country => country === event.target.value
  )
);
Ad
source: stackoverflow.com
Ad