Xin chào👋🏻, Bài viết này được tạo riêng cho những người mới bắt đầu muốn tìm hiểu các phương pháp hiệu quả hơn để quản lý trạng thái giữa nhiều thành phần. Nó cũng nhằm mục đích giải quyết vấn đề phổ biến về việc khoan chống đỡ có thể khiến mã của bạn khó bảo trì và khó hiểu hơn. Hãy bắt đầu với loại vấn đề mà API ngữ cảnh giải quyết. Nếu bạn thích định dạng video thì đây là hướng dẫn mà bạn có thể xem trên kênh YouTube của tôi.👇🏻 https://youtu.be/4p_VWn1AEvg?embedable=true Khoan Prop là gì? Bạn có biết đôi khi bạn cần truyền dữ liệu từ thành phần cha mẹ xuống thành phần con và cuối cùng bạn lại truyền đạo cụ qua một loạt thành phần ở giữa không? Đó gọi là và nó có thể trở nên lộn xộn nhanh chóng. Hãy xem qua một ví dụ để làm rõ điều này. khoan chống đỡ Như được hiển thị trong sơ đồ, hãy tưởng tượng bạn đã tìm nạp một số dữ liệu trong thành phần nằm ở thư mục gốc của ứng dụng. Bây giờ, nếu một thành phần được lồng sâu, chẳng hạn như thành phần , cần truy cập dữ liệu này, thì bạn thường chuyển nó qua các thành phần và dưới dạng đạo cụ trước khi đến được . Điều này có thể trở nên tồi tệ khi ứng dụng của bạn phát triển. App Grandchild Parent Child Grandchild Đây là một cách trình bày trực quan khác: Trong ví dụ trên, thành phần cần dữ liệu người dùng, nhưng dữ liệu này trước tiên phải truyền qua các thành phần và , mặc dù bản thân các thành phần trung gian này không sử dụng dữ liệu. Vì vậy, làm thế nào để chúng ta làm sạch điều này? Đó là lúc API ngữ cảnh phát huy tác dụng. Profile App Navigation Đạo cụ khoan: Tăng khả năng hiển thị lại các thành phần Tăng mã soạn sẵn Tạo sự phụ thuộc thành phần Giảm hiệu suất API bối cảnh phản ứng API ngữ cảnh trong React.js cho phép bạn truyền dữ liệu giữa các thành phần mà không cần truyền dữ liệu dưới dạng đạo cụ qua từng cấp độ của cây thành phần. Nó hoạt động giống như một hệ thống quản lý trạng thái toàn cầu, nơi bạn xác định trạng thái của mình trong một đối tượng ngữ cảnh và sau đó bạn có thể dễ dàng truy cập nó ở bất kỳ đâu trong cây thành phần. Hãy hiểu điều này bằng một ví dụ. Như bạn có thể thấy trong sơ đồ, chúng ta có một đối tượng ngữ cảnh lưu trữ dữ liệu để nhiều thành phần có thể truy cập. Dữ liệu này được lấy từ API hoặc dịch vụ của bên thứ ba. Trước khi truy cập dữ liệu ngữ cảnh này trong bất kỳ thành phần nào, chúng ta cần bao bọc tất cả các thành phần yêu cầu dữ liệu này trong thành phần nhà cung cấp ngữ cảnh. Nếu chúng ta chỉ cần truy cập dữ liệu trong các thành phần điều hướng và hồ sơ, thì chúng ta không cần phải gói thành phần ứng dụng. Khi bạn đã gói các thành phần có liên quan bằng , bạn có thể truy cập trực tiếp vào dữ liệu ngữ cảnh trong bất kỳ thành phần nào sử dụng nó. Đừng lo lắng nếu bạn vẫn chưa hiểu nó; hãy đi sâu vào mã và xem nó hoạt động. ContextProvider Làm cách nào để sử dụng API ngữ cảnh? Đầu tiên, hãy tạo một ứng dụng React bằng . Chỉ cần sao chép các lệnh sau để thiết lập dự án. Vite.js npm create vite@latest Thêm tên dự án của bạn Chọn phản ứng Chọn bản đánh máy từ các tùy chọn cd project_name // to change to project directory npm install npm run dev Sau đó, bạn có thể mở máy chủ phát triển trong trình duyệt của mình. http://localhost:5173 Đầu tiên, hãy tạo các thư mục cần thiết. Đây là cấu trúc thư mục của dự án của chúng tôi. src | components | context Trong thư mục thành phần, hãy tạo tệp và thêm mã sau đây. Profile.jsx import React from 'react' const Profile = () => { return ( <div>Profile</div> ) } export default Profile Tạo thêm một thành phần có tên trong thư mục thành phần. Navbar.jsx import Profile from './Profile' const Navbar = () => { return ( <nav style={{ display: "flex", justifyContent: "space-between", alignItems: "center", width: "90%", height: "10vh", backgroundColor: theme === "light" ? "#fff" : "#1b1b1b", color: theme === "light" ? "#1b1b1b" : "#fff", border: "1px solid #fff", borderRadius: "5px", padding: "0 20px", marginTop: "40px", }}> <h1>LOGO</h1> <Profile /> </nav> ) } export default Navbar Hãy nhập thành phần này vào tệp . <Navbar /> App.jsx import Navbar from "./components/Navbar"; function App() { return ( <main style={{ display: "flex", flexDirection: "column", justifyContent: "start", alignItems: "center", height: "100vh", width: "100vw", }} > <Navbar /> </main> ); } export default App; Như vậy về cơ bản, thành phần là con của và là con của thành phần . <Profile /> <Navbar /> <Navbar /> <App /> Thêm API ngữ cảnh Hãy tạo tệp trong thư mục . Thêm mã sau vào tập tin. UserContext.jsx context import { createContext, useEffect, useState } from "react"; export const UserContext = createContext(); export const UserProvider = ({ children }) => { const [user, setUser] = useState(null); const fetchUserData = async (id) => { const response = await fetch( `https://jsonplaceholder.typicode.com/users/${id}` ).then((response) => response.json()); console.log(response); setUser(response); }; useEffect(() => { fetchUserData(1); }, []); return ( <UserContext.Provider value={{ user, fetchUserData }} > {children} </UserContext.Provider> ); }; Đầu tiên, chúng ta tạo một đối tượng trống bằng cách sử dụng . Chúng tôi đảm bảo nhập nó từ . Chúng ta có thể thêm các giá trị mặc định bên trong đối tượng bối cảnh, nhưng hiện tại chúng ta vẫn giữ nó là null. UserContext createContext react Tiếp theo, chúng ta tạo để trả về một nhà cung cấp bằng cách sử dụng , như . Nó bao quanh các thành phần con và trong giá trị, chúng ta có thể chuyển bất cứ thứ gì chúng ta muốn sử dụng trong các thành phần con. UserProvider UserContext UserContext.Provider Hiện tại, chúng tôi đang sử dụng để tìm nạp dữ liệu người dùng. cung cấp các điểm cuối API giả mạo cho mục đích thử nghiệm. Hàm chấp nhận và sử dụng ID đó để tìm nạp dữ liệu người dùng. Sau đó, chúng tôi lưu trữ phản hồi ở trạng thái . API jsonplaceholder Trình giữ chỗ json fetchUserData id user Chúng tôi đang gọi hàm trong nên khi tải trang, nó sẽ gọi hàm và đưa dữ liệu vào trạng thái . fetchUserData useEffect user Bây giờ, hãy sử dụng bối cảnh này trong thành phần . Gói thành phần bằng cách sử dụng ; giống như đoạn mã sau: <App /> <NavBar /> <UserProvider /> <UserProvider> <Navbar /> </UserProvider> Hãy sử dụng trạng thái trong thành phần . Để làm được điều đó, chúng tôi sẽ sử dụng hook . Điều đó lấy và cung cấp các giá trị mà chúng ta đã chuyển trong , chẳng hạn như trạng thái và hàm . Hãy nhớ rằng, chúng ta không cần bọc thành phần vì nó đã có trong thành phần vốn đã được gói cùng với nhà cung cấp. user <Profile /> useContext UserContext UserProvider user fetchUserData <Profile /> <Navbar /> Mở và thêm đoạn mã sau. Profile.jsx const { user } = useContext(UserContext); if (user) { return ( <span style={{ fontWeight: "bold", }} > {user.name} </span> ); } else { return <span>Login</span>; } Ở đây, chúng tôi đang sử dụng trạng thái từ . Chúng tôi sẽ hiển thị tên người dùng nếu có , nếu không chúng tôi sẽ chỉ hiển thị thông báo đăng nhập. Bây giờ, nếu bạn thấy kết quả đầu ra thì phải có tên người dùng trong thành phần thanh điều hướng. Đây là cách chúng ta có thể trực tiếp sử dụng bất kỳ trạng thái nào trong ngữ cảnh của bất kỳ thành phần nào. Thành phần sử dụng trạng thái này phải được gói trong . user UserContext user <Provider /> Bạn cũng có thể sử dụng nhiều bối cảnh. Bạn chỉ cần bọc các thành phần nhà cung cấp trong một thành phần nhà cung cấp khác như trong ví dụ sau. <ThemeProvider> <UserProvider> <Navbar /> </UserProvider> </ThemeProvider> Trong ví dụ trên, chúng tôi đang sử dụng để quản lý trạng thái chủ đề. <ThemeProvider /> Bạn có thể xem video youtube ở trên để xem ví dụ đầy đủ về việc sử dụng nhiều nhà cung cấp ngữ cảnh. Tối ưu hóa kết xuất lại trong API bối cảnh phản ứng Có một vấn đề xảy ra khi bạn sử dụng API ngữ cảnh trong nhiều thành phần. Bất cứ khi nào trạng thái hoặc giá trị thay đổi trong API ngữ cảnh, nó sẽ hiển thị lại tất cả các thành phần đã đăng ký với ngữ cảnh cụ thể đó, ngay cả khi không phải tất cả các thành phần đều đang sử dụng trạng thái đã thay đổi. Để hiểu vấn đề kết xuất lại này, hãy tạo một thành phần sử dụng ngữ cảnh để lưu trữ và hiển thị các giá trị đếm. <Counter /> Hãy xem ví dụ sau. Bạn có thể tạo tệp trong thư mục thành phần và dán đoạn mã sau. Counter.jsx import { createContext, memo, useContext, useState } from "react"; const CountContext = createContext(); const CountProvider = ({ children }) => { const [count, setCount] = useState(0); return ( <CountContext.Provider value={{ count, setCount }}> {children} </CountContext.Provider> ); }; function CountTitle() { console.log("This is Count Title component"); return <h1>Counter Title</h1>; } function CountDisplay() { console.log("This is CountDisplay component"); const { count } = useContext(CountContext); return <div>Count: {count}</div>; } function CounterButton() { console.log("This is CounterButton component"); const { count, setCount } = useContext(CountContext); return ( <> <CountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </> ); } export default function Counter() { return ( <CountProvider> <CounterButton /> </CountProvider> ); } Trong đoạn mã trên: Đầu tiên, chúng ta tạo một đối tượng bằng CountContext createContext. Trong chúng ta có một trạng thái để lưu trữ các giá trị đếm. Chúng ta đang gửi và phương thức tới các thành phần con thông qua value prop. CountProvider, count setCount Chúng tôi đã tạo các thành phần riêng biệt để xem số lần hiển thị lại các thành phần riêng lẻ. : Thành phần này chỉ hiển thị tiêu đề và thậm chí không sử dụng bất kỳ giá trị nào từ ngữ cảnh. <CountTitle /> : Thành phần này hiển thị các giá trị đếm và sử dụng trạng thái từ ngữ cảnh. <CountDisplay /> count : Thành phần này hiển thị cả thành phần trên và nút tăng giá trị đếm bằng cách sử dụng . <CounterButton /> setCount Cuối cùng, chúng tôi gói thành phần trong thành phần để các thành phần khác có thể truy cập vào các giá trị đếm. <CounterButton /> CountProvider Bây giờ, nếu bạn chạy mã và nhấp vào nút , bạn sẽ thấy trong nhật ký rằng mọi thành phần đều hiển thị lại mỗi khi trạng thái thay đổi. thậm chí không sử dụng các giá trị đếm nhưng nó đang hiển thị lại. Điều này xảy ra vì thành phần chính của là đang sử dụng và cập nhật giá trị của count và đó là lý do hiển thị lại. Increase <CountTitle /> <CountTitle /> <CounterButton /> Làm thế nào chúng ta có thể tối ưu hóa hành vi này? Câu trả lời là . React cho phép bạn bỏ qua việc hiển thị lại một thành phần khi đạo cụ của nó không thay đổi. Sau thành phần , hãy thêm dòng sau. memo memo <CountTitle /> const MemoizedCountTitle = React.memo(CountTitle) Bây giờ, trong thành phần , nơi chúng ta đang hiển thị thành phần , hãy thay thế bằng như trong đoạn mã sau: <CounterButton /> <CountTitle /> <CountTitle /> <MemoizedCountTitle /> <> <MemoizedCountTitle /> <CountDisplay /> <button onClick={() => setCount(count + 1)}>Increase</button> </> Bây giờ, nếu bạn tăng số lượng và kiểm tra nhật ký, bạn sẽ có thể thấy rằng nó không hiển thị thành phần nữa. <CountTitle /> API Redux và API ngữ cảnh là một thư viện quản lý trạng thái để quản lý trạng thái phức tạp với các chuyển đổi trạng thái dễ dự đoán hơn. Trong khi API bối cảnh được thiết kế để quản lý trạng thái đơn giản và truyền dữ liệu qua cây thành phần mà không cần khoan prop. Vậy khi nào nên chọn cái nào? Redux Sử dụng để quản lý trạng thái đơn giản, cục bộ trong đó trạng thái không thường xuyên thay đổi. React Context API Sử dụng cho các nhu cầu quản lý trạng thái phức tạp, đặc biệt là trong các ứng dụng lớn hơn, nơi lợi ích của việc quản lý trạng thái có cấu trúc vượt trội hơn so với thiết lập bổ sung. Redux Ngoài ra còn có một thư viện nữa cũng là một lựa chọn phổ biến cho việc quản lý state. . Phản ứng giật lại là một thư viện quản lý trạng thái dành cho React nhằm mục đích cung cấp sự đơn giản của API bối cảnh với sức mạnh và hiệu suất của Redux. React Recoil Nếu bạn muốn tìm hiểu thêm về , hãy cho tôi biết trong phần nhận xét và tôi sẽ tạo các hướng dẫn chuyên sâu về chủ đề này dựa trên phản hồi của bạn. React Recoil Phần kết luận API bối cảnh cung cấp một cách mạnh mẽ và hiệu quả để quản lý trạng thái trên nhiều thành phần, giải quyết hiệu quả vấn đề khoan chống đỡ. Bằng cách sử dụng API ngữ cảnh, bạn có thể đơn giản hóa mã của mình, giảm việc hiển thị lại không cần thiết và cải thiện hiệu suất ứng dụng tổng thể. React.js Mặc dù API bối cảnh lý tưởng cho việc quản lý trạng thái đơn giản, nhưng các ứng dụng phức tạp hơn có thể được hưởng lợi từ việc sử dụng hoặc các thư viện quản lý trạng thái khác như . Hiểu thời điểm và cách sử dụng các công cụ này sẽ cho phép bạn xây dựng các ứng dụng React dễ bảo trì và mở rộng hơn. Redux React Recoil Cảm ơn bạn đã đọc bài viết này, tôi hy vọng bạn thấy nó hữu ích. Nếu bạn quan tâm đến việc học và xây dựng các dự án bằng React, Redux và Next.js, bạn có thể truy cập kênh YouTube của tôi tại đây: CodeBucks Dưới đây là các bài viết khác của tôi mà bạn có thể muốn đọc: Cách triển khai tính năng cuộn mượt mà trong Next.js bằng Lenis và GSAP Cách lấy vị trí của người dùng trong React.js Top 10 Theme VS Code Phổ Biến Bạn Nên Thử Ghé thăm blog cá nhân của tôi: DevDreaming