Search code examples
javascriptreactjsreduxuse-refreact-forwardref

React UseRef and forwardRef issue for an element position


I have successfully connected my component Details.js in order to manage the state out of the component itself, these are the steps:

You can see the demo here

Details.js

import React, { useState, useEffect, useRef, ref, useImperativeHandle, forwardRef } from "react";

  const cleanValue = () => {
    setDataHomeTeam([]);
    setDataAwayTeam([]);
  };

  useImperativeHandle(fowardedRef, () => {
    return {
      cleanValue: cleanValue
    };
  });

const ConnectedDetails = connect(
  mapStateToProps,
  mapDispatchToProps,
  null
)(Details);

export default forwardRef((props, ref) => {
  return <ConnectedDetails {...props} fowardedRef={ref} />;
});

App.js

const ref = useRef();  
<button onClick={() => ref.current.cleanValue()} type="button">Reset</button>
<Details ref={ref} />

It works ,the demo is here.

My problem is when i move this element from App.js to Leagues.js as you can see in the demo ( there are both cases )

Leagues.js

Line 71

<button onClick={() => ref.current.cleanValue()} type="button">Reset</button>

i get this error when i click on it => TypeError Cannot read property 'cleanValue' of undefined

Is it possible ? If yes, what am i doing wrong and how can i fix that?


Solution

  • As pointed out in the comments, the main issue was that the ref reference within the Leagues component was not pointing to the Details component.

    The following 3 modifications to your original code can be done to make the button in the Leagues component work:

    1. Adding an onReset property to the Leagues component

       let Leagues = ({
             getList,
             getStats,
             leaguesList,
             loading,
             getDetail,
             teamsDetail,
             onReset
           })
      
    2. using the onReset function in the Leagues component

      Original: <button onClick={() => ref.current.cleanValue()} type="button">

      New: <button onClick={onReset} type="button">

    3. setting the onReset property of the Leagues component to a function which will call the cleanValue() method of the Details component

      Original: <Leagues />

      New: <Leagues onReset={() => ref.current.cleanValue()} />

    The full code can be found here.

    Please note that from architectural perspective, it is not recommended for a component to access its sibling via reference. Many scenarios where this seems needed might be better dealt with via the parent component.