2

I've got a container div with a lot of children, and an overflow-x set to scroll.

This allows me to scroll the content to the left and right using my trackpad (or drag on mobile).

But I really would like the default scroll position to be the maximum horizontal value. (i.e. scrolled all the way to the right). The relevant code for this is Element.scrollLeft = <some large value>.

I'm trying to figure out how to achieve this with React and callback refs. I have the following code:

const containerRef = useCallback(
  (node) => {
    if (node !== null) {
      node.scrollLeft = values.length * 20;
    }
  },
  [values.length]
);
return (
    <div className={"scroll-wrapper"} ref={containerRef}>
      values.map(()=>{
        // Some stuff in here that's irrelevant.
      });
    </div>
)

(This code was based on https://reactjs.org/docs/hooks-faq.html#how-can-i-measure-a-dom-node)

When I put a breakpoint in the useCallback function, I see it is properly invoked with a non-0 value, but right after the call when I inspect node.scrollLeft it is still 0.

When I inspect the DOM in Chrome, I can actually force the scrollLeft of the element to be high number, which does work.

So why doesn't the React useCallback ref work?

2 Answers 2

1

You should use useRef hook to work with refs.

To create ref use this:

const containerRef = useRef();

And add it to ref of div as you did before:

<div className={"scroll-wrapper"} ref={containerRef}>
  ...
</div>

And you should use useEffect and call it one time to set scrollLeft to the component in ref:

useEffect(() => {
  ref.current.scrollLeft = 4000;
}, []);

Here is the full example: https://codesandbox.io/s/lingering-glitter-s0gok?file=/src/App.js

Sign up to request clarification or add additional context in comments.

1 Comment

I appreciate the answer, and while it is correct, so is my original code. I actually find the useCallback approach a bit more elegant as you get a direct reference to the node itself. This does actually work. I tried your answer and I got the same results. After long debugging it turns out the problem was unrelated. It was due to an animation framework I'm using that created elements with a delay + in combination with absolute positioning of my child elements. I'll update the question for it to be more accurate.
1

This is how I fixed

then just make some css issue for that

  const [scrollX, setScrollX] = useState({
    side: ""
  });
  const scrollLeftRef = useRef();
  const handleScroll = (data) => {
    setScrollX(prev => ({ ...prev, side: data.side }));
  }
  useEffect(() => {
    if (scrollX.side === "right") {
      scrollLeftRef.current.scrollLeft += 200;
    } else {
      scrollLeftRef.current.scrollLeft -= 200;
    }
  }, [scrollX]);
   <div class="slide-sample">
            <div id="slideRight" onClick={() => handleScroll({ side: "left" })} class="preSlide">
              <i className="fas fa-caret-square-left" />
            </div>
            <div ref={scrollLeftRef} class="slideouter">
              <div class="slideinner srcl">
                <ul>
                  {
                    categories.map((category, i) => {
                      return (

                        <Button
                          key={category.id}
                          onClick={() => { dispatch(filterfood(category.name)); handleItemClick(i) }}
                          variant={activeclass === i ? "contained" : "outlined"}
                          size="medium"
                        >
                          {category.name}
                        </Button>
                      )
                    })}
                </ul>
              </div>
            </div>
            <div id="slideRight" onClick={() => handleScroll({ side: "right" })} className="nextSlide">

              <i className="fas fa-caret-square-right" />
            </div>

          </div>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.