React Hook [useState]:更新状态并重新呈现视图

时间:2019-12-24 07:43:11

标签: reactjs react-hooks

经验:我是React的初学者。

我想学习的东西:钩子(useState)-但我不知道如何更新状态并以此来重新呈现视图。据我了解,如果更新后的状态与上一个相似,React不会重新渲染视图。在谷歌搜索之后,我试图复制状态并以某种方式对其进行更新,但是我丢失了一些内容,我不知道什么。

我要在项目中尝试做的事情:当用户从下拉菜单中选择区域时,我有一个要过滤的国家/地区列表。发生选择时,将触发此函数,并附上一些注释,希望这些注释可以解释我要执行的操作:

    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);
    };

您可以找到有问题的文件和代码HERE(向下滚动至change函数)

  1. 从“按地区列出的Fitler”中选择一个地区

  2. 在控制台中查看错误/输出

1 个答案:

答案 0 :(得分:1)

您正在将状态更新为对象数组,最后一项将是过滤后的列表

相反,传入包含已过滤国家/地区的单个数组。

请注意,由于您正在修改整个国家/地区,因此您第二次选择其他地区时,您的州将丢失。

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

那么我们能避免失去状态吗?

我们可以根据所选区域过滤列表。

在我更改代码的地方添加了注释

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);
}