Skip to content

Instantly share code, notes, and snippets.

@jamsesso
Created December 9, 2018 15:38
Show Gist options
  • Save jamsesso/7aa94a2a7ccaa33968b6eaca974d4c21 to your computer and use it in GitHub Desktop.
Save jamsesso/7aa94a2a7ccaa33968b6eaca974d4c21 to your computer and use it in GitHub Desktop.
Managing component state in the URL with react-router
import React from 'react';
import withUrlState from './with-url-state';
function Example({urlState, setUrlState}) {
const {count} = urlState;
return <button onClick={() => setUrlState({count: count + 1})}>{count}</button>;
}
export default withUrlState({count: 0})(Example);
import React, {Component} from 'react';
import {withRouter} from 'react-router-dom';
import queryString from 'query-string';
function withUrlState(initialState = {}) {
return C => withRouter(class WithUrlState extends Component {
static displayName = `withUrlState(${C.displayName || C.name})`;
// Callbacks to invoke when the URL changes.
listeners = [];
componentDidUpdate(prevProps) {
const {location: {search}} = this.props;
if (prevProps.location.search !== search) {
this.listeners.forEach(f => f(this.getUrlState()));
}
}
handleSetUrlState = (nextUrlState, method = 'replace') => {
const {history, location} = this.props;
const currentUrlState = queryString.parse(location.search);
const nextQueryString = {
...currentUrlState,
...(typeof nextUrlState === 'function' ? nextUrlState(currentUrlState) : nextUrlState)
};
history[method](`?${queryString.stringify(nextQueryString)}`);
};
getUrlState = () => {
const {location} = this.props;
return {
...initialState,
...queryString.parse(location.search)
};
}
handleUrlStateChange = f => {
this.listeners.push(f);
}
render() {
return (
<C
{...this.props}
urlState={this.getUrlState()}
setUrlState={this.handleSetUrlState}
onUrlStateChange={this.handleUrlStateChange}
/>
);
}
});
}
export default withUrlState;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment