如何在 React js 中使用获取的数据过滤数组?

How to filter an array with fetched data in React js?

我正在尝试通过在输入中输入用户编号来过滤获取的博客 posts。此数字应与 post 用户 ID 匹配,并仅显示该给定用户的 posts 'written'(从 1 到 10 的数字,每个用户有 10 posts ).

问题:当我在输入中输入数字时,posts 消失并且不过滤任何内容。我很确定我坚持使用过滤功能。

提前致谢!

function App(pst) {

  const [posts, setPosts] = useState([]);
  const [query, setQuery] = useState('');

  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts/')
      .then(response => response.json())
      .then(json => setPosts(json))
  }, [])

  return (
    <ThemeProvider theme={theme}>
      <CssBaseline />
      
      <Router>
          <NavBar />
          <Switch>
            <Route exact path='/'>
              <Home />
              <SearchBar 
              value={query}
              onChange={(e) => setQuery(e.target.value)}
              />
              <Grid container spacing={2} justify='center'>
                {posts.filter((val) => {
                  if (query === '') {
                    return val
                  } else if (query === val.userId) {
                    return val
                  }
                  console.log(query);
                }).map((pst) => (
                  <PostCard pst={pst} key={pst.id}/>
                ))}
              </Grid>
            </Route>
            <Route exact path='/singlePost/:postId' component={SinglePost} />
            <Route exact path='/PostList'>
              <PostList pst={pst}/>
            </Route>
          </Switch>
      </Router>
    </ ThemeProvider>
  );
}

过滤数据的方式主要有两种:客户端或服务器端。有时,在处理大型数据集和复杂数据结构时,服务器端的性能可能更高。在您的示例中,数据非常小且数据结构非常扁平,因此客户端过滤就足够了。

首先是第一件事,因为您希望过滤所有呈现给客户端的数据,所以您需要将该数据存储到它自己的 posts 状态。然后,您将拥有某种 searchValue 状态,只要用户更改 input 值,该状态就会发生变化。利用这两种状态,您可以使用 searchValue 过滤 posts 并将结果存储到它自己的 filteredPosts 状态。

React 只会在 stateprops 更改时重新渲染组件。因此,您需要利用状态更改来使您的组件保持最新状态。

工作演示

代码

App.js

import * as React from "react";
import "./styles.css";

export default function App() {
  const [searchValue, setSearch] = React.useState(0);
  const [posts, setPosts] = React.useState([]);
  const [filteredPosts, setFilteredPosts] = React.useState([]);

  const handleSearchChange = (event) => {
    /*
      This "handleSearchChange" is a callback function that accepts an
      "event" as an argument. 

      This "event" contains the "input" DOM element. And this
      element contains a "value" property that is stored as 
      a string on the "target" property. This "event.target.value"
      will update the input's "searchValue" state.

      Please note, "event.target.value" will be a string and when
      filtering the post's "id", which is a number, a string value of "1" 
      won't equal a post id of number 1! Therefore, parseInt(string, 10)
      coverts the string value to a number value.
    */
    setSearch(parseInt(event.target.value, 10));
  };

  const handleSearchReset = () => {
    setSearch(0);
  };

  React.useEffect(() => {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((response) => response.json())
      .then((json) => setPosts(json));
  }, []);

  React.useEffect(() => {
    /*
      When the searchValue changes, filter the posts by id with
      searchValue and store the result to "filteredPosts"
    */
    setFilteredPosts(posts.filter((post) => post.id === searchValue));
  }, [posts, searchValue]);

  return (
    <div className="App">
      <h1>Search Posts</h1>
      <input
        min={0}
        value={searchValue}
        type="number"
        onChange={handleSearchChange}
      />
      <br />
      <button type="button" onClick={handleSearchReset}>
        Reset Search
      </button>
      <h1>Filtered Posts</h1>
      <pre className="code">
        <code>{JSON.stringify(filteredPosts, null, 2)}</code>
      </pre>
      <h1>Available Posts</h1>
      <pre className="code">
        <code>{JSON.stringify(posts, null, 2)}</code>
      </pre>
    </div>
  );
}

index.js

import * as React from "react";
import ReactDOM from "react-dom";
import App from "./App";

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