Search code examples
reactjsreact-hooksuse-effectrefuse-ref

How to pass data got from useEffect down a component tree(got undefined)


I want to make a specific calculation in Search component. To do this, I have to pass a buttonSearchRefOffsetLeftValue obtained in the Header component to a Search component. I get the desired value in the Header. However in the Search component it always gets undefined. Can't understand this behavior.

const Header = props => {
     const buttonSearchRef = useRef(null);

     let buttonSearchRefOffsetLeftValue;

     useEffect(() => {
         buttonSearchRefOffsetLeftValue = 
         ReactDOM.findDOMNode(buttonSearchRef.current).offsetLeft;
         console.log(buttonSearchRefOffsetLeftValue); //got the value
      })

   return (
      <div ref={buttonSearchRef}>He<div>
             <Search buttonSearchRefOffsetLeftValue= 
          {buttonSearchRefOffsetLeftValue} />
       ) 
     }

 const Search = (props) => {
     console.log(props.buttonSearchRefOffsetLeftValue)//got undefined WHY?
 }

Solution

  • The reason is when you declare it first like this, its value will be undefined by default

     let buttonSearchRefOffsetLeftValue;
    

    Then, it will pass this value first to Search component before the useEffect of Header is run. Thats why you get undefined. AFter that, when the DOM is fully rendered, the ref is attached, useEffect runs and update buttonSearchRefOffsetLeftValue, but this is not a React state or props. Therefore, it not update props.buttonSearchRefOffsetLeftValue in Search, resulting it still keeps undefined.

    A quick fix for this is to put buttonSearchRefOffsetLeftValue in a state

    export const Header = (props) => {
      const buttonSearchRef = useRef(null);
    
      const [ buttonSearchRefOffsetLeftValue, setButtonSearchRefOffsetLeftValue] = useState(null);
    
      useEffect(() => {
          setButtonSearchRefOffsetLeftValue(ReactDOM.findDOMNode(buttonSearchRef.current).offsetLeft);
          console.log('head', buttonSearchRefOffsetLeftValue); //got the value
      });
    
      return (<div>
        <div ref={buttonSearchRef}>He</div>
        <Search buttonSearchRefOffsetLeftValue={buttonSearchRefOffsetLeftValue}/></div>);
      }
    

    now your Search component should log the console twice, with the second time printing out the value.