简体   繁体   中英

React Hook [useState]: update state and rerender the view

Experience : I am a total beginner in React.

What I am trying to learn: Hooks ( useState ) - but I do not know how to update the state and rerender the view with this. As far as I understood React does not rerender the view if the updated state is somewhat similar to the last one... After googling, I tried to copy the state and update it somehow, but I am missing something, and I do not know what.

What I am trying to do in the project : I have a list of countries I want to filter through when the user selects a region from a dropdown. This is the function that gets fired when the selection happens, along with comments that I hope explain what I am trying to do:

    const change = event => {
        //copy the `data` state (which has a list of all the countries)
        let newData = [...data];
        console.log(newData);

        //filter through the countries list to get only those with the selected region
        let filtered = newData.filter(obj => obj.region === event.target.value);
        console.log(filtered);

        //change the countries list with the filtered one, and rerender the view
        setData([data, newData]);
        console.log(data);
    };

You can find the file and the code in questionHERE (scroll down to get to the change function)

  1. Select a region from the 'Fitler by region dropdown'

  2. See the errors/outputs in the console

You are updating the state to an array of objects and the last item will be the filtered list

Instead, pass in a single array that holds the filtered countries.

Note that your state will be lost the second time you select a different region because you are modifying the entire collection of countries.

setData(data.filter(obj => obj.region === event.target.value))

So what you can we to avoid losing the state?

We can filter the list based on the selected region.

Added comments where i changed the code

export default function CountriesList() {
  const [data, setData] = useState([]);
  const [distinctRegions, setDistinctRegions] = useState([]);
  const [loading, setLoading] = useState(true);
  // added state to track the selected region
  const [selectedRegion, setSelectedRegion] = useState("");

  useEffect(() => {
    CountriesAPI().then(res => {
      onLoad(res);
      setLoading(false);
    });
  }, []);

  const onLoad = dataList => {
    setData(...data, dataList);
    getRegions(dataList);
  };

  const getRegions = dataList => {
    let regions = [];

    dataList.map(dataItem =>
      dataItem.region.length ? regions.push(dataItem.region) : ""
    );

    let regionsFiltered = regions.filter(
      (item, index, arr) => arr.indexOf(item) === index
    );

    setDistinctRegions(...distinctRegions, regionsFiltered);
  };

  const renderLoading = () => {
    return <div>Loading...</div>;
  };

  // now we only need to update the selected region
  const change = event => {
    setSelectedRegion(event.target.value);
  };

  const renderData = (dataList, distinctRegionsItem) => {
    if (dataList && dataList.length) {
      return (
        <div>
          <Container>
            <Input type="text" placeholder="Search for a country..." />
            <Select className="select-region" onChange={change}>
              <option value="" hidden>
                Filter by region
              </option>
              // added show all
              <option value="">Show All</option>
              {distinctRegionsItem.map(item => {
                return (
                  <option key={item} value={item}>
                    {item}
                  </option>
                );
              })}
            </Select>
          </Container>
          <CardList>
            // filter the array based on selectedRegion and then render the list.
            // if selectedRegion is empty show all
            {dataList
              .filter(
                country => !selectedRegion || country.region === selectedRegion
              )
              .map(country => (
                <CountryCard
                  population={country.population}
                  region={country.region}
                  capital={country.capital}
                  flag={country.flag}
                  key={country.alpha3Code}
                  id={country.alpha3Code}
                  name={country.name}
                />
              ))}
          </CardList>
        </div>
      );
    } else {
      return <div>No items found</div>;
    }
  };

  return loading ? renderLoading() : renderData(data, distinctRegions);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM