像专业人士一样使用 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;
状态(“searchQuery”)实际上是我们在 SearchResult.js 组件中过滤产品或其他内容所需要的。
实现这一目标的方法
- 在 App.js 中定义 state 和 setState 函数,将它们作为 props 传递给 Layout.js,进一步传递给 Header.js,最后传递给 SearchBar.js 组件。现在,使用 setState 函数返回 App.js 组件并更改 state。
或者
- 使用上下文 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();
现在,让我们创建一个“上下文”以及 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;
附言:不要被 createContext 函数中的冗余代码弄糊涂了。它完全是可选的。
我写这个是为了更好的智能感知和代码补全。
这也很好用!
export const SearchContext = React.createContext();
使用上下文
使用 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);
};
...
}
使用 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;
这将复制 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;
只是一个简单的过滤逻辑,检查“标题”或“标签”是否包含存储在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 (
...
)
}
只是一个简单的过滤逻辑,检查“标签”或“标题”是否包含存储在searchContext.query变量中的字符串。
非常感谢你的阅读
很想听听你的想法
鏂囩珷鏉ユ簮锛�https://dev.to/holdmypotion/using-react-context-api-like-a-pro-13k5