如何为高阶组件(HOC)创建共享状态?LoadBookHOC场景咨询
Got it, let's figure out how to make your LoadBookHOC share state across all wrapped components. Right now, every component you wrap with LoadBookHOC gets its own instance of the LoadBook class—so their book states are totally isolated from each other. Here are two reliable approaches to fix this:
Approach 1: Use React Context (Recommended)
React Context is the official way to share state across components without passing props down manually. It's perfect for this scenario because it lets all wrapped components access the same shared state and update function.
Step 1: Create a Book Context
First, make a dedicated context to hold your shared book state and update logic:
// BookContext.js import React, { createContext, useState, useContext } from 'react'; // Create the context const BookContext = createContext(); // Provider component that manages the shared state export const BookProvider = ({ children }) => { const [book, setBook] = useState([]); // Match the existing `hocSetState` interface your components use const hocSetState = (obj) => { if (obj.book !== undefined) { setBook(obj.book); } }; return ( <BookContext.Provider value={{ hocState: { book }, hocSetState }}> {children} </BookContext.Provider> ); }; // Custom hook to easily access the context in components export const useBookContext = () => useContext(BookContext);
Step 2: Update LoadBookHOC to Use the Context
Modify your HOC to pull state and the update function from the context instead of managing its own local state:
// LoadBookHOC.js import React from 'react'; import { useBookContext } from './BookContext'; const LoadBookHOC = InnerComponent => { return function LoadBook(props) { const { hocState, hocSetState } = useBookContext(); return <InnerComponent {...props} hocState={hocState} hocSetState={hocSetState} />; }; }; export default LoadBookHOC;
Step 3: Wrap Your App with the Provider
In your app's root component, wrap all components that need access to the shared state with BookProvider:
// App.js import { BookProvider } from './BookContext'; import BookDetails from './BookDetails'; import BookSummary from './BookSummary'; function App() { return ( <BookProvider> <BookDetails /> <BookSummary /> </BookProvider> ); }
Now, whenever BookDetails or BookSummary calls this.hocSetState({ book: <new data> }), both components will receive the updated shared book state automatically.
Approach 2: Use a Singleton State Manager
If you prefer not to use Context, you can create a singleton object to hold the shared state and manage subscriptions for updates. This works, but requires a bit more manual work to trigger component re-renders.
Step 1: Create a Singleton State Manager
// BookStateManager.js let bookState = []; let subscribers = []; export const BookStateManager = { // Get the current state getState: () => ({ book: bookState }), // Update state and notify subscribers setState: (obj) => { if (obj.book !== undefined) { bookState = obj.book; subscribers.forEach(callback => callback()); } }, // Let components subscribe to state changes subscribe: (callback) => { subscribers.push(callback); // Return a function to unsubscribe when the component unmounts return () => { subscribers = subscribers.filter(sub => sub !== callback); }; } };
Step 2: Update LoadBookHOC to Use the Singleton
// LoadBookHOC.js import React, { useEffect, useState } from 'react'; import { BookStateManager } from './BookStateManager'; const LoadBookHOC = InnerComponent => { return function LoadBook(props) { // Use a dummy state to force re-renders when state changes const [, forceUpdate] = useState(); useEffect(() => { // Subscribe to state changes and trigger re-render when updates happen const unsubscribe = BookStateManager.subscribe(() => forceUpdate({})); // Clean up the subscription when the component unmounts return unsubscribe; }, []); const hocState = BookStateManager.getState(); const hocSetState = BookStateManager.setState; return <InnerComponent {...props} hocState={hocState} hocSetState={hocSetState} />; }; }; export default LoadBookHOC;
This way, all wrapped components will share the same book state stored in the singleton. When any component updates the state, all subscribed components will re-render with the new state.
Final Notes
I'd recommend going with the React Context approach—it's more aligned with React's design patterns, easier to maintain, and works seamlessly with React's lifecycle and hooks. The singleton approach is okay for small apps, but can get messy as your app grows.
内容的提问来源于stack exchange,提问作者Balasubramanian

