Search code examples
javascriptreactjsscrollcomponents

How to scroll to a component from another component in React?


I have a form that, on submission displays the results of the form, but more importantly, scrolls to a component that shows the results. I am stuck trying to pass in refs and forward refs. All of the demos I've seen have been of components in the same file. My setup is as follows:

The App.js holds two components– Form.js which submits the form and Results.js which displays the results of the form submission. The Results.js component is further down the page so I want to scroll to that component once the user clicks enter on the form.

Here is a codesandbox that demonstrates my setup.

Here is the same code on here:

// App.js
import "./styles.css";
import Form from "./Form";
import Results from "./Results";

export default function App() {
  return (
    <>
      <Form />
      <Results />
    </>
  );
}
// Form.js
import { forwardRef, useState } from "react";

const Form = forwardRef(({ onScroll }, ref) => {
  const [name, setName] = useState("");

  const onSubmit = (e) => {
    e.preventDefault();
    onScroll();
  };

  return (
    <form onSubmit={onSubmit} className="tall">
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <button type="submit">Submit</button>
    </form>
  );
});

export default Form;


// Results.js

import { useRef } from "react";
export default function Results() {
  const resultsRef = useRef();

  function handleScrollToResults() {
    resultsRef.current.scrollIntoView({ behavior: "smooth" });
  }

  return (
    <div onScroll={handleScrollToResults}>
      <h1>Results</h1>
    </div>
  );
}


Solution

  • Few things to be corrected.

    1. Results component should forward the ref, not to the Form component.
    import { forwardRef } from "react";
    
    const Results = forwardRef((props, ref) => {
      return (
        <div ref={ref}>
          <h1>Results</h1>
        </div>
      );
    });
    
    export default Results;
    
    1. Form component should receive the ref to Results as a prop (resultRef).
    import { useState } from "react";
    
    const Form = ({ resultRef }) => {
      const [name, setName] = useState("");
    
      const onSubmit = (e) => {
        e.preventDefault();
        resultRef.current.scrollIntoView({ behavior: "smooth" });
      };
    
      return (
        <form onSubmit={onSubmit} className="tall">
          <input value={name} onChange={(e) => setName(e.target.value)} />
          <button type="submit">Submit</button>
        </form>
      );
    };
    
    export default Form;
    
    1. Root component should create the ref using useRef and use it as below. Notice that Form is using the resultRef while Results is instantiating it.
    import "./styles.css";
    import Form from "./Form";
    import Results from "./Results";
    import { useRef } from "react";
    
    export default function App() {
      const resultRef = useRef(null);
    
      return (
        <>
          <Form resultRef={resultRef} />
          <Results ref={resultRef} />
        </>
      );
    }
    

    Edit Scroll Component (forked)