Source:  Twitter logo

I have a /cart route that accepts a couple of query params called validate and email. They’re only used when a user isn’t logged in and are unnecessary when they are. In the latter case I would like to remove them from the URL.

This is my current onEnter function for the /cart route:

const requireCartLogin = (props, replace) => {
    const { email, validate } = props.location.query;

    // Exit process if the 'validate' query isn’t present.
    if (typeof validate === 'undefined') { return; }

    if (!isAuthenticated() || requiresReauthentication()) {
        replace({
            pathname: '/account/signin',
            query: { step: 'signin' },
            state: {
                email: typeof email !== 'undefined' ? email : null,
                auth: true,
                next: '/cart'
            }
        });
    } else if (isAuthenticated()) {
        replace({
            pathname: '/cart',
            query: null
        });
    }
};

It’s that second part of the conditional that should be removing the query params, but it isn’t currently working. What am I missing here?

Have a look at Dimitry Dushin's example

Create 2 utility functions like this:

import { browserHistory } from 'react-router';

/**
 * @param {Object} query
 */
export const addQuery = (query) => {
  const location = Object.assign({}, browserHistory.getCurrentLocation());

  Object.assign(location.query, query);
  // or simple replace location.query if you want to completely change params

  browserHistory.push(location);
};

/**
 * @param {...String} queryNames
 */
export const removeQuery = (...queryNames) => {
  const location = Object.assign({}, browserHistory.getCurrentLocation());
  queryNames.forEach(q => delete location.query[q]);
  browserHistory.push(location);
};

And use it to manipulate the query as in the example shown below:

import { withRouter } from 'react-router';
import { addQuery, removeQuery } from '../../utils/utils-router';

function SomeComponent({ location }) {
  return <div style={{ backgroundColor: location.query.paintRed ? '#f00' : '#fff' }}>
    <button onClick={ () => addQuery({ paintRed: 1 })}>Paint red</button>
    <button onClick={ () => removeQuery('paintRed')}>Paint white</button>
  </div>;
}

export default withRouter(SomeComponent);

Note that this will not work in >v4 of react-router.

1 users liked answer #0dislike answer #01
Chetan Jadhav CD profile pic
Chetan Jadhav CD

i searched for a while on how to do this and ended up realizing all i need to do is just use history to push to the url like i normally do (without the params):

// this piece of code is in /app/settings/account
React.useEffect(() => {

        let params = queryString.parse(location.search)
        if (params && params.code) {
            doSomething(params.code)                                                            
            history.push('/app/settings/account')           
        }
    
}, [])
1 users liked answer #1dislike answer #11
Jar profile pic
Jar

Assuming react-router-dom

Removing is the trickiest part , so first you need to be able to get the current params in a sensible format.

You can get the search params as a string via the useLocation hook.

But working with a string like this is confusing, I prefer to deal with an object.

For example ?filter=123&filter=something&page=1 would produce the following object.

{
    filter: ['123', 'something'],
    page: ['1']
}

Much easier to manipulate.

So we should create 2 utility functions , one to convert a search string into the above object, and one to convert an object back into a search string.

toParamObject.js

const toParamObject = (queryString) => {
  const params = new URLSearchParams(queryString);
  let paramObject = {};
  params.forEach((value, key) => {
    if (paramObject[key]) {
      paramObject = {
        ...paramObject,
        [key]: [
          ...paramObject[key],
          value,
        ],
      };
    } else {
      paramObject = {
        ...paramObject,
        [key]: [value],
      };
    }
  });

  return paramObject;
};

toQueryString.js

const toQueryString = (paramObject) => {
  let queryString = '';
  Object.entries(paramObject).forEach(([paramKey, paramValue]) => {
    if (paramValue.length === 0) {
      return;
    }
    queryString += '?';
    paramValue.forEach((value, index) => {
      if (index > 0) {
        queryString += '&';
      }
      queryString += `${paramKey}=${value}`;
    });
  });

  // This is kind of hacky, but if we push '' as the route, we lose 
  // our page, and base path etc.
  // So instead.. pushing a '?' just removes all the current query strings
  return queryString !== '' ? queryString : '?';
};

get

// search is from useLocation, and we can just pass in the name of the param we want
const get = (key) => toParamObject(search)[key] || [];

remove

const remove = (key, value) => {
    // First get the current params get()
    const thisParam = get(param).filter((val) => val !== value);
    const newParamObject = {
      ...toParamObject(search), // from useLocation
      [param]: thisParam,
    };
    push(`${toQueryString(newParamObject)}`); // from useHistory
};
0 users liked answer #2dislike answer #20
Daniel Cooke profile pic
Daniel Cooke

You could simply overwrite search param in history.push like below:

history.push({
    pathname: 'what/ever/your/path/is',
    search: '',
});
0 users liked answer #3dislike answer #30
Sajad Rezvani profile pic
Sajad Rezvani

If using react-router-dom, you can remove it using history.replace.

const history = useHistory();
const location = useLocation();

const removeAllSearchParams = () => {
    history.replace({
        pathname: location.pathname,
        search: '',
    })
}

return (
    <button onClick={() => removeAllSearchParams()}
       Remove Search Params
    </button>
)
0 users liked answer #4dislike answer #40
Devin Clark profile pic
Devin Clark

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).