title: useEffect hook fix dependency array when a route is changed
body: <p>I'm facing a problem with the functional component. I'm using a <code>react-router-dom</code> package for handling the routes. What I have is a list that contains links and buttons and when we click on the button a dropdown is opened. This dropdown also contains links. </p>
  
  <ul>
  <li>Whenever user will change the route all dropdowns will close.</li>
  <li>Whenever new dropdown is opened all others will also close.</li>
  </ul>
  
  <p><strong>How I'm manging the state of these dropdowns?</strong> </p>
  
  <p>I'm treating the state of every dropdown as a separate object and <code>onClick</code> listener will pass a <code>key</code> / <code>property</code> as an argument that has a boolean value. Based on that value a class will be added on the dropdown.</p>
  
  <p>I already achieve this with the help of a class component.</p>
  
  <p><strong>Class component:</strong></p>
  
  <pre><code>import React, { Component } from "react";
  import { Link, withRouter } from "react-router-dom";
  
  class ToggleClass extends Component {
      state = {};
  
      toggle = dropdownName =&gt; {
          // If it has the true value then turn into false, It is a behavior of a toggle.
          if (this.state[dropdownName]) {
              this.setState({ [dropdownName]: false });
          }
          // If there is not any dropdown is opened it means state object is empty
          // Object.keys will return an empty array then please open that dropdown.
          else if (Object.keys(this.state).length === 0) {
              this.setState({ [dropdownName]: true });
          }
          // Else block will ony trigger when the user clicked on other dropdown,
          // then close the last dropdown and just open the new one
          else {
              Object.keys(this.state).forEach(i =&gt; {
                  this.setState({ [i]: false });
              });
              this.setState({ [dropdownName]: true });
          }
      };
  
      onRouteChanged = () =&gt; {
          // Take a state object and convert all its keys into an array
          // and set it to false whenever a route changes.
          Object.keys(this.state).forEach(i =&gt; {
              // pageMenu: false
              this.setState({ [i]: false });
          });
      };
  
      componentDidUpdate(prevProps, prevState, snapshot) {
          if (this.props.location !== prevProps.location) {
              this.onRouteChanged();
          }
      }
  
      componentDidMount() {
          this.onRouteChanged();
      }
  
      render() {
          return (
              &lt;ul className="list"&gt;
                  &lt;li&gt;
                      &lt;Link to="/link1"&gt;Link 1&lt;/Link&gt;
                  &lt;/li&gt;
  
                  &lt;li&gt;
                      &lt;button onClick={() =&gt; this.toggle("dropdown1")}&gt;Dropdown 1&lt;/button&gt;
  
                      &lt;ul className={this.state["dropdown1"] ? "open" : "hide"}&gt;
                          &lt;li&gt;
                              &lt;Link to="/link2"&gt;Link 2&lt;/Link&gt;
                          &lt;/li&gt;
                          &lt;li&gt;
                              &lt;Link to="/link3"&gt;Link 3&lt;/Link&gt;
                          &lt;/li&gt;
                      &lt;/ul&gt;
                  &lt;/li&gt;
  
                  &lt;li&gt;
                      &lt;button onClick={() =&gt; this.toggle("dropdown2")}&gt;Dropdown 2&lt;/button&gt;
  
                      &lt;ul className={this.state["dropdown2"] ? "open" : "hide"}&gt;
                          &lt;li&gt;
                              &lt;Link to="/link4"&gt;Link 4&lt;/Link&gt;
                          &lt;/li&gt;
                          &lt;li&gt;
                              &lt;Link to="/link5"&gt;Link 5&lt;/Link&gt;
                          &lt;/li&gt;
                      &lt;/ul&gt;
                  &lt;/li&gt;
              &lt;/ul&gt;
          );
      }
  }
  
  export default withRouter(ToggleClass);
  </code></pre>
  
  <p>But the problem is on the functional component by using hooks. <code>react-router-dom</code> has a hook named <a href="https://reacttraining.com/react-router/web/api/Hooks/uselocation" rel="nofollow noreferrer">useLocation</a> which returns the current <code>pathname</code>. But <code>onRouteChanged</code> function is updating the state. I cannot use this function inside <code>useEffect</code> hook it turns into an infinite loop.</p>
  
  <pre><code>useEffect(() =&gt; {
    onRouteChanged();
  }, [location, onRouteChanged]);
  </code></pre>
  
  <p>But If I remove the <code>onRouteChanged</code> from the dependency array then linter will warn about this</p>
  
  <p><code>React Hook useEffect has a missing dependency: 'onRouteChanged'. Either include it or remove the dependency array react-hooks/exhaustive-deps</code></p>
  
  <pre><code>useEffect(() =&gt; {
    onRouteChanged();
  }, [location]);
  </code></pre>
  
  <p><strong>Functional Component:</strong></p>
  
  <pre><code>import React, { useEffect, useState } from "react";
  import { Link, useLocation } from "react-router-dom";
  
  const ToggleFunc = () =&gt; {
    const location = useLocation();
    const [state, setState] = useState({});
  
    const onRouteChanged = () =&gt; {
      Object.keys(state).forEach(i =&gt; {
        setState({ [i]: false });
      });
    };
  
    const toggle = dropdownName =&gt; {
      if (state[dropdownName]) {
        setState({ [dropdownName]: false });
      } else if (Object.keys(state).length === 0) {
        setState({ [dropdownName]: true });
      } else {
        Object.keys(state).forEach(i =&gt; {
          setState({ [i]: false });
        });
        setState({ [dropdownName]: true });
      }
    };
  
    useEffect(() =&gt; {
      onRouteChanged();
    }, [location]);
  
    return (
      &lt;ul className="list"&gt;
        &lt;li&gt;
          &lt;Link to="/link1"&gt;Link 1&lt;/Link&gt;
        &lt;/li&gt;
  
        &lt;li&gt;
          &lt;button onClick={() =&gt; toggle("dropdown1")}&gt;Box 1&lt;/button&gt;
  
          &lt;ul className={state["dropdown1"] ? "open" : "hide"}&gt;
            &lt;li&gt;
              &lt;Link to="/link2"&gt;Link 2&lt;/Link&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;Link to="/link3"&gt;Link 3&lt;/Link&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/li&gt;
  
        &lt;li&gt;
          &lt;button onClick={() =&gt; toggle("dropdown2")}&gt;Box 2&lt;/button&gt;
  
          &lt;ul className={state["dropdown2"] ? "open" : "hide"}&gt;
            &lt;li&gt;
              &lt;Link to="/link4"&gt;Link 4&lt;/Link&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;Link to="/link5"&gt;Link 5&lt;/Link&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/li&gt;
      &lt;/ul&gt;
    );
  };
  
  export default ToggleFunc;
  </code></pre>
  
  <p>Can you guide me What is the optimal way to fix these errors?</p>
  
  <p><a href="https://codesandbox.io/s/solo98989-vjgi0" rel="nofollow noreferrer">Full example Codesandbox</a></p>