14

I want to monitor hash change and then change the state and rerender the component. so I want to know where to monitor the hash change in component lifecycle

example:

#/detail/:id  =>  #/detail

{info:[a:1,b:2]} => {info:[]}

.#/detail/:id and #/detail are the same components

李明洋
  • 541
  • 3
  • 6
  • 17

4 Answers4

21

If you want your component to have event listeners, you want to add those event listeners in componentDidMount, and remove the event listeners in componentWillUmount.

componentDidMount() {
    window.addEventListener("hashchange", this.doSomething, false);
}

componentWillUnmount() {
    window.removeEventListener("hashchange", this.doSomething, false);
}
captray
  • 3,618
  • 1
  • 18
  • 15
  • 1
    I know this way, but the #/detail and #/detial/:id is the same component.so the method componentDidMount only once, When I visited #/detail:id it was finished. so when I visit the #/detail is not working。 – 李明洋 Aug 16 '16 at 03:01
  • I would recommend you look at https://github.com/reactjs/react-router, but if you're trying to roll your own, you should have a parent component created as I described. It's also difficult to offer a more robust answer based on your post. Not sure what you mean with the :id. if you're trying to create your own custom hash based routing, again, I recommend react-router. – captray Aug 16 '16 at 03:15
  • sorry, my english is not good. I'm using react-router. Thank you – 李明洋 Aug 16 '16 at 03:18
  • When i used the `componentDidMount` it fires twice, one for the previous url state and another for the new url state with the new hash, – Si8 Apr 01 '19 at 14:41
4

For React newer version

Use window.location.hash with useEffect

useEffect( ()=> {
        doSomething();
  }, [window.location.hash])
GMKHussain
  • 3,342
  • 1
  • 21
  • 19
3

Use HashRouter in index.js and withRouter to get path parameters and getDerivedStateFromProps to handle the states based on the url's hash.

index.js

import ReactDOM from 'react-dom';
import { HashRouter } from "react-router-dom";

import App from './App';

ReactDOM.render(
  <HashRouter>
    <App />
  </HashRouter>,
  document.getElementById('root')
);

App.js

import { withRouter } from 'react-router-dom';

class App extends Component {

  state = { productId: null };

  static getDerivedStateFromProps(nextProps){
    const { location: { pathname } } = nextProps;       // pathname e.g.: '/detail/:8'
    const productId = pathname.split(':')[1] || null;   // ProductId: 8 OR null;
    return { productId };
  }

  ...

}

export default withRouter(App);
gazdagergo
  • 6,187
  • 1
  • 31
  • 45
1

If you want to monitor the change in route params you may do that it the lifecycle method componentWillReceiveProps

componentWillReceiveProps

Use this as an opportunity to react to a prop transition before render() is called by updating the state using this.setState(). The old props can be accessed via this.props. Calling this.setState() within this function will not trigger an additional render.

componentWillReceiveProps: function(nextProps) {
  const {params: {id}} = nextProps;
  if(id !== this.props.params.id){
    /////////
  }
}
Deadfish
  • 2,047
  • 16
  • 17
  • This is the correct way to do it in react. I used this to detect hash change and scroll to specific element depending on hash value. – Indigo Apr 27 '17 at 15:03
  • Doesn't this assume you're using ReactRouter (or something similar) though? – cdeutsch Oct 08 '18 at 17:51