title: How to scroll a React page when it loads?
body: <p>I want to pass a value as the hash in the url (myapp.com#somevalue) and have the page scroll to that item when the page loads - exactly the behavior of using a hash fragment since the beginning of the internet. I tried using scrollIntoView but that fails on iOS. Then I tried just unsetting/setting window.location.hash but there seems to be a race condition. It only works when the delay is more than 600ms.</p>
  
  <p>I would like a more solid solution and don't want to introduce an unnecessary delay. When the delay is too short, it appears to scroll to the desired item but then scrolls to the top of the page. You won't see the effect on this demo but it happens in my actual app <a href="https://codesandbox.io/s/pjok544nrx" rel="noreferrer">https://codesandbox.io/s/pjok544nrx</a> line 75</p>
  
  <pre><code>  componentDidMount() {
      let self = this;
  
      let updateSearchControl = hash =&gt; {
        let selectedOption = self.state.searchOptions.filter(
          option =&gt; option.value === hash
        )[0];
        if (selectedOption) {
          // this doesn't work with Safari on iOS
          // document.getElementById(hash).scrollIntoView(true);
  
          // this works if delay is 900 but not 500 ms
          setTimeout(() =&gt; {
            // unset and set the hash to trigger scrolling to target
            window.location.hash = null;
            window.location.hash = hash;
            // scroll back by the height of the Search box
            window.scrollBy(
              0,
              -document.getElementsByClassName("heading")[0].clientHeight
            );
          }, 900);
        } else if (hash) {
          this.searchRef.current.select.focus();
        }
      };
  
      // Get the hash
      // I want this to work as a Google Apps Script too which runs in
      // an iframe and has a special way to get the hash
      if (!!window["google"]) {
        let updateHash = location =&gt; {
          updateSearchControl(location.hash);
        };
        eval("google.script.url.getLocation(updateHash)");
      } else {
        let hash = window.location.hash.slice(1);
        updateSearchControl(hash);
      }
    }
  </code></pre>
  
  <p>EDIT: I tracked down the line of React that re-renders the page and consequently resets the scroll position after it already scrolled where I told it to go in componentDidMount(). It's <a href="https://github.com/facebook/react/blob/21d5f7d32d5becf5c8e986ff0202059be643dc15/packages/react-dom/src/shared/CSSPropertyOperations.js#L82" rel="noreferrer">this one</a>.
  <code>style[styleName] = styleValue;</code> At the time the page is re-rendered it is setting the width style property of the inputbox component of the react-select box component. The stack trace right before it does this looks like</p>
  
  <pre><code>(anonymous) @   VM38319:1
  setValueForStyles   @   react-dom.development.js:6426
  updateDOMProperties @   react-dom.development.js:7587
  updateProperties    @   react-dom.development.js:7953
  commitUpdate    @   react-dom.development.js:8797
  commitWork  @   react-dom.development.js:17915
  commitAllHostEffects    @   react-dom.development.js:18634
  callCallback    @   react-dom.development.js:149
  invokeGuardedCallbackDev    @   react-dom.development.js:199
  invokeGuardedCallback   @   react-dom.development.js:256
  commitRoot  @   react-dom.development.js:18867
  (anonymous) @   react-dom.development.js:20372
  unstable_runWithPriority    @   scheduler.development.js:255
  completeRoot    @   react-dom.development.js:20371
  performWorkOnRoot   @   react-dom.development.js:20300
  performWork @   react-dom.development.js:20208
  performSyncWork @   react-dom.development.js:20182
  requestWork @   react-dom.development.js:20051
  scheduleWork    @   react-dom.development.js:19865
  scheduleRootUpdate  @   react-dom.development.js:20526
  updateContainerAtExpirationTime @   react-dom.development.js:20554
  updateContainer @   react-dom.development.js:20611
  ReactRoot.render    @   react-dom.development.js:20907
  (anonymous) @   react-dom.development.js:21044
  unbatchedUpdates    @   react-dom.development.js:20413
  legacyRenderSubtreeIntoContainer    @   react-dom.development.js:21040
  render  @   react-dom.development.js:21109
  (anonymous) @   questionsPageIndex.jsx:10
  ./src/client/questionsPageIndex.jsx @   index.html:673
  __webpack_require__ @   index.html:32
  (anonymous) @   index.html:96
  (anonymous) @   index.html:99
  </code></pre>
  
  <p>I don't know where to move my instruction to scroll the page. It has to happen after these styles are set which is happening after componentDidMount().</p>
  
  <p>EDIT: I need to better clarify exactly what I need this to do. Apologies for not doing that before.</p>
  
  <h3>Must haves</h3>
  
  <p>This has to work on all common desktop and mobile devices.</p>
  
  <p>When the page loads there could be three situations depending on what query is provided in the url after the #: </p>
  
  <ul>
  <li>1) no query was provided - nothing happens</li>
  <li>2) a valid query was provided - the page scrolls instantly to the desired anchor and the page's title changes to the label of the option</li>
  <li>3) an invalid query was provided - the query is entered into the search box, the search box is focused and the menu opens with options limited by the provided query as if they had been typed in. The cursor is located in the search box at the end of the query so the user can modify the query.</li>
  </ul>
  
  <p>A valid query is one that matches the value of one of the options. An invalid query is one that doesn't.</p>
  
  <p>The browser back and forward buttons should move the scroll position accordingly.</p>
  
  <p>Any time an option is chosen from the Search box the page should scroll instantly to that anchor, the query should clear returning to the placeholder "Search...", the url should update, and the document's title should change to the option's label.</p>
  
  <h3>Optional but would be great</h3>
  
  <p>After making a selection the menu closes and the query goes back to "Search...", and either</p>
  
  <ul>
  <li>the Search box retains the focus so the user can begin typing another query. The next time it is <strong>clicked</strong>, the menu opens, and the Searchbox query from before the selection, the menu's filter and the menu scroll position are restored (most preferred), or</li>
  <li>the Search box loses focus. The next time it is <strong>focused</strong>, the menu opens, and the Search box query from before the selection, the menu's filter and the menu scroll position are restored (preferred), or</li>
  <li>the Search box retains the focus so the user can begin typing another query. The prior query and menu scroll position are lost.</li>
  </ul>