简体   繁体   English

过滤数组然后映射它不使用 React Hooks 显示结果

[英]Filtering an array and then mapping it isn't displaying results with React Hooks

import React, { useState, useEffect } from "react";
import axios from "axios";

const App = () => {
  let [countries, setCountries] = useState([]);
  const [newCountry, newStuff] = useState("");
  const hook = () => {
    //console.log("effect");
    axios.get("https://restcountries.eu/rest/v2/all").then((response) => {
      console.log("promise fulfilled");
      setCountries(response.data);
      //console.log(response.data);
    });
  };

  const filter = (event) => {
    newStuff(event.target.value);

    if (event.target.value === undefined) {
      return
    } else {
      let value = event.target.value;
      console.log(value);
      countries = countries.filter((country) => country.name.startsWith(value));
      setCountries(countries);
      console.log(countries);
    }
  };
  useEffect(hook, []);
  return (
    <div>
      <p>find countries</p>
      <input value={newCountry} onChange={filter} />
      <ul>
        {countries.map((country) => (
          <li key={country.name.length}>{country.name}</li>
        ))}
      </ul>
    </div>
  );
};
export default App;

So I have a search bar so that when you enter a few characters it will update the state and show the countries that start with the respective first characters.所以我有一个搜索栏,这样当您输入几个字符时,它会更新 state 并显示以相应第一个字符开头的国家/地区。 However, nothing is being shown when I enter input into my search bar.但是,当我在搜索栏中输入输入时,没有显示任何内容。 Also, my filter function, when I console.log my countries array which is supposed to have the countries that start with the characters I entered, it's always an empty array.另外,我的过滤器 function,当我 console.log 我的国家/地区数组应该以我输入的字符开头的国家/地区时,它始终是一个空数组。

You need some changes in order to make this work:您需要进行一些更改才能使其正常工作:

  1. Use two states for countries, one for the list you get in the initial render and another for the current filter countries.对国家使用两种状态,一种用于您在初始渲染中获得的列表,另一种用于当前过滤器国家。

     const [countriesStore, setCountriesStore] = useState([]); // this only change in the first render const [countries, setCountries] = useState([]); // use this to print the list

    I recomed to use any tool to manage the state and create a model for the countries ther you can make the side effect there and create an action that update the countries store.我建议使用任何工具来管理 state 并为国家/地区创建 model,然后您可以在那里产生副作用并创建更新国家/地区存储的操作。 I'm using Easy Peasy in my current project and it goes very well.我在我当前的项目中使用Easy Peasy ,效果很好。

  2. Take care of the filter method because startsWith method is not case-insensitive.注意 filter 方法,因为 startsWith 方法不区分大小写。 You need a regular expression or turn the current country value to lower case.您需要正则表达式或将当前国家/地区值转换为小写。 I recommend to use includes method to match seconds names like island in the search.我建议在搜索中使用包含方法来匹配像 island 这样的秒名称。

     const filterCountries = countriesStore.filter(country => { return country.name.toLowerCase().includes(value); });
  3. Remove the if condition in the filter in order to include the delete action in the search and get the full list again if everything is removed.删除过滤器中的 if 条件,以便在搜索中包含删除操作,并在删除所有内容时再次获取完整列表。

  4. Just in the case, empty the search string state in the first render以防万一,在第一次渲染中清空搜索字符串 state

    useEffect(() => { hook(); setSearchString(""); }, []); useEffect(() => { hook(); setSearchString(""); }, []);

  5. Replace the length in the list key.替换列表键中的长度。 You can use the name and trim to remove space.您可以使用名称和修剪来删除空格。

    <li key={country.name.trim()}>{country.name}</li>

The final code look like this:最终代码如下所示:

export default function App() {
  const [countriesStore, setCountriesStore] = useState([]);
  const [countries, setCountries] = useState([]);
  const [searchString, setSearchString] = useState("");

  const hook = () => {
    axios.get("https://restcountries.eu/rest/v2/all").then(response => {
      console.log("promise fulfilled");
      setCountriesStore(response.data);
      setCountries(response.data);
    });
  };

  const filter = event => {
    setSearchString(event.target.value);

    let value = event.target.value;

    const filterCountries = countriesStore.filter(country => {
      return country.name.toLowerCase().includes(value);
    });

    setCountries(filterCountries);
  };

  useEffect(() => {
    hook();
    setSearchString("");
  }, []);

  return (
    <div>
      <p>find countries</p>
      <input value={searchString} onChange={filter} />
      <ul>
        {countries.map(country => (
          <li key={country.name.trim()}>{country.name}</li>
        ))}
      </ul>
    </div>
  );
}

You need to wrap your hook into async useCallback:您需要将您的钩子包装到异步 useCallback 中:

const hook = useCallback(async () => {
    const {data} = await axios.get("https://restcountries.eu/rest/v2/all");
    setCountries(data);
}, []);

you are not able to mutate state countries.您无法改变 state 国家/地区。 Use immutable way to update your state:使用不可变的方式更新您的 state:

const filter = (event) => {
    newStuff(event.target.value);

    if (event.target.value === undefined) {
      return
    } else {
      let value = event.target.value;
      setCountries(countries.filter((country) => country.name.startsWith(value)));
    }
};

And useState is asynchronous function.useState是异步的function。 You will not see result immediately.您不会立即看到结果。 Just try to console.log outside of any function.只需尝试在任何 function 之外访问 console.log。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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