Skip to content

[Feature]: <Routes> onChange props please #9688

@AntiMoron

Description

@AntiMoron

What is the new or updated feature that you are suggesting?

interface RouterState {
  location: Location;
  params: Params;
}

interface RoutesProps {
  children?: React.ReactNode;
  location?: Partial<Location> | string;
  // I'm going to add this
  onChange?: (prevState: RouterState, nextState: RouterState) => void;
}

<Routes onChange={(prevState, nextState) => {
   // prevState.location; same as useLocation
  // prevState.params; same as useParams
}}>
  <Route element={<XX1 />} route="/xxx1" />
  <Route element={<XX2 />} route="/xxx2" />
  <Route element={<XX3 />} route="/xxx3" />
</Routes>

Why should this feature be included?

What is not enough?

With the current API, you cannot detect path changing before it actually happens. You can only know it afterwards with useLocation and useEffect.

Why I need it, show some scenarios:

Usually, we need to know when the route changes as we need to fetch API results with different parameters. We'll code like this:

// <Route  element={<DetailPage />} path="/item/:itemId" />
// localhost:3000/#/item/10001?filters={"price":">100$"}

const location = useLocation();
const params = useParams();

useEffect(() => {
  const itemId =  params.itemId;
  const pathname = location.pathname;
  // get extra params from hash query, pass it as a request parameter.
  request('/some/api/for/itemDetial', parse(location.search).filters).then((data) => { // filters as a parameter.
    setState(data);
  });
}, [location, params]);

As there's some new data flow library as recoil by Facebook which is based on observer pattern, requests are usually bound with state changes, like:

// atom.ts
const filter = atom({ key: 'filterParamKey', default: undefined });
const getDetail = selector({
  key: 'getDetailSelector',
  get: async ({ get }) => {  // this function will be triggered for every atom involved in with the `get` method changes.
    const filterValue = get(filter);
    return await request('/some/api/for/itemDetial', filterValue);
  }
});

// component.tsx
const location = useLocation();
const params = useParams();
const setFilterState = useSetRecoilState(filter); // components just need to focus on setting values with `recoil`.
useEffect(() => {
  setFilterState(parse(location.search).filters);
}, [location, params]);

In this case, request is triggered instantly when the filter state changes.
If you route as below:

  1. navigate to #/item/10001?filters=xxxx
  2. navigate to #/randompage // which clears the filter state.
  3. click prev of the browser and find out filter parameter is lost.

How to fix it with onChange property

const location = useLocation();
const params = useParams();
const setFilterState = useSetRecoilState(filter); // components just need to focus on setting values with `recoil`.
return <Routes onChange={(prev, next) => {
  setFilterState(parse(next.location.search).filters);
}}>

</Routes>

Metadata

Metadata

Assignees

No one assigned

    Labels

    feature-requestUsed to close PRs that haven't gone through/been accepted the Proposal process yet

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions