像专业人士一样使用 React Context API Context API 背后的概念考虑这个例子使用 Context 创建 Context

2025-06-08

像专业人士一样使用 React Context API

Context API 背后的概念

考虑这个例子

创建上下文

使用上下文

如果你听说过“Context API”这个词,并且对它感到一头雾水(就像我前几天那样),或者你根本不知道它是什么意思,不用再找了!我已经帮你搞定了(我相信大部分情况下是这样)。

Context API 背后的概念

需要注意的是:即使没有 Context API,你也可以通过常规的“prop 钻取”方式很好地工作。Context API 只做一件事,那就是“降低不相关组件之间的耦合”。

React 组件应该只包含其运行所需的逻辑。
一个组件对应一个角色。(请注意,“角色”高度依赖于你创建组件所执行的任务类型)

每个 React 程序都有一些组件,这些组件保存着程序所依赖的某些状态。这些状态通过“props”从“父组件”传递给“子组件”。

现在,在不一定具有父子关系的组件之间传递状态是通过上下文 API 来处理的。

考虑这个例子

看看下面的组件图

替代文本

这里,组件树中的 SearchBar.js 组件具有接收用户搜索输入的状态

// SearchBar.js

import React, { useState } from "react";
import { Link } from "react-router-dom";

import styles from "./SearchBar.module.css";
import SearchLogo from "../../assets/search.svg";

const SearchBar = (props) => {
  const [searchQuery, setSearchQuery] = useState("");

  return (
    <div className={styles.searchBar}>
      <input
        placeholder="Search"
        type="text"
        className={styles.input}
        onChange={(e) => setSearchQuery(e.target.value)}
        value={searchQuery}
      />
      <Link
        to="/search-result"
      >
        <img src={SearchLogo} alt="Search Logo | magnifying glass" />
      </Link>
    </div>
  );
};

export default SearchBar;
Enter fullscreen mode Exit fullscreen mode

状态(“searchQuery”)实际上是我们在 SearchResult.js 组件中过滤产品或其他内容所需要的。

实现这一目标的方法

  1. 在 App.js 中定义 state 和 setState 函数,将它们作为 props 传递给 Layout.js,进一步传递给 Header.js,最后传递给 SearchBar.js 组件。现在,使用 setState 函数返回 App.js 组件并更改 state。

或者

  1. 使用上下文 API!!!

创建上下文

我们首先需要定义上下文。我喜欢的做法是创建一个 HOC(高阶组件),用来包装 App 组件。

就像这样...

(看到 SearchContextProvider 组件时不要感到困惑。我们马上就会定义它。)

// index.js

import React from "react";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";

import SearchContextProvider from "./context/search-context";

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

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
Enter fullscreen mode Exit fullscreen mode

现在,让我们创建一个“上下文”以及 SearchContextProvider 组件

SearchContextProvider 只是一个简单的 HOC 组件,但具有一个特殊功能,即它使用 Context.Provider 包装子组件。

需要注意的最重要的事情是 SearchContext.Provider 上的值属性。(在代码中)
无论您在值属性中输入什么,它都会对子组件可用。

现在您可以在 App 组件内的任何组件中使用“query”状态和“searchHandler”函数

import React, { useState } from "react";

// query is the state
// SearchHandler is a function for changing the state.
export const SearchContext = React.createContext({
  query: "",
  searchHandler: () => {},
});

// Defining a simple HOC component
const SearchContextProvider = (props) => {
  const [query, setQuery] = useState("");

  const searchHandler = (query) => {
    setQuery(query);
  };

  return (
    <SearchContext.Provider
      value={{ query: query, searchHandler: searchHandler }}
    >
      {props.children}
    </SearchContext.Provider>
  );
};

export default SearchContextProvider;
Enter fullscreen mode Exit fullscreen mode

附言:不要被 createContext 函数中的冗余代码弄糊涂了。它完全是可选的。
我写这个是为了更好的智能感知和代码补全。

这也很好用!

export const SearchContext = React.createContext();
Enter fullscreen mode Exit fullscreen mode

使用上下文

使用 context 非常直观,而且非常简单。
就像使用其他状态或函数一样!

我们想要添加到 SearchBar.js 组件的新行

...
import React, { useState, useContext } from "react";
import { SearchContext } from "../../context/search-context";
...

const SearchBar = (props) => {
...
  const searchContext = useContext(SearchContext);

  const searchQueryHandler = () => {
    searchContext.searchHandler(searchQuery);
  };
...
}
Enter fullscreen mode Exit fullscreen mode

使用 context API 的 SearchBar.js 看起来像这样

// SearchBar.js

import React, { useState, useContext } from "react";
import { Link } from "react-router-dom";

import { SearchContext } from "../../context/search-context";
import styles from "./SearchBar.module.css";
import SearchLogo from "../../assets/search.svg";

const SearchBar = (props) => {
  const [searchQuery, setSearchQuery] = useState("");
  const searchContext = useContext(SearchContext);

  const searchQueryHandler = () => {
    searchContext.searchHandler(searchQuery);
  };

  return (
    <div className={styles.searchBar}>
      <input
        placeholder="Search"
        type="text"
        className={styles.input}
        onChange={(e) => setSearchQuery(e.target.value)}
        value={searchQuery}
      />
      <Link
        to="/search-result"
        onClick={searchQueryHandler}
      >
        <img src={SearchLogo} alt="Search Logo | magnifying glass" />
      </Link>
    </div>
  );
};

export default SearchBar;
Enter fullscreen mode Exit fullscreen mode

这将复制 searchQuery 状态并将其存储在我们的小上下文中定义的查询变量中。

现在我们可以在任何地方使用相同的状态

// SearchResult.js

import React, { useContext } from "react";
import { SearchContext } from "../../context/search-context";

import styles from "./SearchResult.module.css";
import ProductSection from "../../components/ProductSection/ProductSection";

const SearchResult = ({ products, ...props }) => {
  const searchContext = useContext(SearchContext);
  let filteredProducts;
  if (products) {
    filteredProducts = products.filter((product) => {
      if (
        product.title.toLowerCase().includes(searchContext.query) ||
        product.tags.toLowerCase().includes(searchContext.query)
      ) {
        return product;
      }
      return null;
    });
  }
  return (
    <div>
      <div className={styles.title}>
        <h1>Search Results</h1>
      </div>
      <div className={styles.container}>
        {filteredProducts && (
          <ProductSection
            products={filteredProducts}
            sectionSlug="search-result"
          />
        )}
      </div>
    </div>
  );
};

export default SearchResult;
Enter fullscreen mode Exit fullscreen mode

只是一个简单的过滤逻辑,检查“标题”或“标签”是否包含存储在searchContext.query变量中的字符串。

上述代码中需要关注的行。

import React, { useContext } from "react";
import { SearchContext } from "../../context/search-context";
...

const SearchResult = ({ products, ...props }) => {
  const searchContext = useContext(SearchContext);

  let filteredProducts;
  if (products) {
    filteredProducts = products.filter((product) => {
      if (
        product.title.toLowerCase().includes(searchContext.query) ||
        product.tags.toLowerCase().includes(searchContext.query)
      ) {
        return product;
      }
      return null;
    });
  }
return (
  ...
)

}
Enter fullscreen mode Exit fullscreen mode

只是一个简单的过滤逻辑,检查“标签”或“标题”是否包含存储在searchContext.query变量中的字符串。

非常感谢你的阅读

很想听听你的想法

鏂囩珷鏉ユ簮锛�https://dev.to/holdmypotion/using-react-context-api-like-a-pro-13k5
PREV
Docker CMD 与 ENTRYPOINT:解释差异
NEXT
如何在 React 和 NextJS 中使用 ThreeJS