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

75 views Asked by At

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?
 }
2

There are 2 answers

0
Jake Lam On BEST ANSWER

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.

1
Viet Dinh On

You may have noticed that. Console log will print in order like:

undefined

0

This mean useEffect always be called after return function. I suggest you should have state for buttonSearchRefOffsetLeftValue to pass it child component. Put your variable dependencies will make effect to buttonSearchRefOffsetLeftValue in useEffect.

My demo:

const Search = (props) => {
    console.log('value'+ props.buttonSearchRefOffsetLeftValue)//got undefined WHY?
    return <div/>
}

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

    const [buttonSearchRefOffsetLeftValue, setButtonSearchRefOffsetLeftValue] = useState(null);

    useEffect(() => {
        let buttonSearchRefOffsetLeftValue = ReactDOM.findDOMNode(buttonSearchRef.current).offsetLeft;
        setButtonSearchRefOffsetLeftValue(buttonSearchRefOffsetLeftValue);
        console.log(buttonSearchRefOffsetLeftValue); //got the value
    }, [
        //put some dependencies will effect your buttonSearchRefOffsetLeftValue
    ])

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