Raul
Raul

Reputation: 3081

React - When to use useImperativeHandle?

When should I use the hook useImperativeHandle?

I mean, I think there are multiple ways to use it, and that it is useful to access child state or child methods from a parent component...

So... imagine this situation:

I have a screen "Profile", which implements a pull-to-refresh to update the user data and posts. Posts are rendered in a child component "UserPosts", where I fetch the respective posts of a user (pagination, listeners, ...).

If the Profile screen is the one responsible of fetching the user data and render the <RefreshControl />, should I pass a ref to my child in order to do userPostsRef.current.fetchNewPosts() from the parent?

Something like:

      function Profile({ userId }) {
         const { userData, fetchUserData } = useFetchUserData(userId);
    
         const [isRefreshing, setIsRefreshing] = useState(false);
    
         const userPostsRef = useRef(null);
    
         const handleOnRefresh = async () => { // simplified, no mutex, no error catching
           setIsRefreshing(true);
    
           const promises = [
              fetchUserData(),
              userPostsRef.current.fetchNewPosts()
           ];
    
           await Promise.all(promises);
    
           setIsRefreshing(false);
         }
    
         ...
    
         const renderFooter = () => <UserPosts ref={userPostsRef} userId={userId} />
    
         return (
            <FlatList
               refreshing={isRefreshing}
               onRefresh={handleOnRefresh}
               ListHeaderComponent={renderHeader()}
               ListFooterComponent={renderFooter()}
            />
         );
      }
      const UserPosts = forwardRef({ userId }, ref) => {
         const { posts, isLoading, fetchNewPosts, fetchMoreOldPosts } = useFetchUserPosts(userId);
    
         useImperativeHandle(ref, {
             fetchNewPosts,
         });
    
         return <CardList data={posts} isLoading={isLoading} ... />;
      }

Upvotes: 1

Views: 3065

Answers (2)

Jarrod McGuire
Jarrod McGuire

Reputation: 683

I have used it in a couple of scenarios that seemed to make sense to me. One was to trigger a handler inside a reusable component outside of that component - a reset button. All of the logic regarding the reset and fetching data was held within the component and it didn't make sense to have that logic and data either (a) in the store (b) on the pages that needed to use the component (c) in a context provider which added more jank.

The second reason, was to fetch information from inside the component (I hear you gasp!), but in this instance the content (rich text editor RTE) was triggered from a "save" button, but I wanted it to be part of a whole form submit. Because of the nature of the component (and probably to do with my limited understanding of the way things work), I couldn't hook it into the form framework I was using, and the method to parse the RTE into raw html for saving on the server was too expensive for key press changes (again, this might have been mitigated by more knowledge about how things hook together).

Anyway, I have an a demo showing a couple of examples showing how to trigger an action inside a component (pretty much what the op posted) and also how to get info back out of the component when the content inside might be asynchronous in nature.

https://codesandbox.io/s/useimperitivehandle-double-example-71oxwm?file=/src/App.tsx

Upvotes: 0

Michael Sherris Caley
Michael Sherris Caley

Reputation: 342

It's not clear whether you're asking if this is the correct use case or simply when is a good time to use useImperativeHandle and then giving an example.


For when to use useImperativeHandle I'd point you to this answer


And in response to the example you gave, I wouldn't try to use useImperativeHandle. Instead I would move the logic for fetching posts to the parent and then pass the data down to the child component.

Upvotes: 0

Related Questions