What is the usage of material-ui useScrollTrigger with child target ref?

Viewed 11359

I am trying to use material-ui's useScrollTrigger with a target other than window like so:

export default props => {
    let contentRef = React.createRef();

    const scrollTrigger = useScrollTrigger({ target: contentRef.current });

    return (
        <React.Fragment>
            <CustomHeader shrink={scrollTrigger} />

            <div ref={contentRef}>
                {props.children}
            </div>
        </React.Fragment>
    );
};

This causes an error to be thrown because contentRef.current is null when useScrollTrigger is called. What is the proper usage of this utility with child elements as a target?

3 Answers

You were right, since the first time the component renders contentRef.current is null and so an error will be thrown.

We need two things a reference to the target Element, and a way to re-render so our scrollTrigger is calculated again. in other words we need a state.

The following code will work

export default props => {

    // please keep it undefined here to not make useScrollTrigger throw an error on first render 
    const [scrollTarget, setScrollTarget] = useState(undefined) 
    const scrollTrigger = useScrollTrigger({ target: scrollTarget });

    return (
        <React.Fragment>
            <CustomHeader shrink={scrollTrigger} />

            <div ref={node => {
                if (node) {
                    setScrollTarget(node);
                }
            }}>
                {props.children}
            </div>
        </React.Fragment>
    );
};

For you typescript users that feel left out, let me save you several hours of your lives figuring out the appropriate typing:

const [scrollTarget, setScrollTarget] = useState<Node | Window | undefined>()
const scrollTrigger = useScrollTrigger({ target: scrollTarget });

I would try something like this:

 const scrollTrigger = useScrollTrigger(() => {{ target: contentRef.current }});
Related