Skip to content

Commit 728a5c1

Browse files
authored
Add new hooks - useQueryParam and usePathParam (#42)
* Add new hook - useQueryParam * Move push logic to actions, usePathParam api, docs and tests * Add one more test — multiple hooks used in the same component
1 parent 2683ee1 commit 728a5c1

File tree

19 files changed

+1013
-11
lines changed

19 files changed

+1013
-11
lines changed

docs/api/hooks.md

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,59 @@ export const RouterActionsHookExample = () => {
6161
return <MyComponent push={push} />;
6262
};
6363
```
64+
65+
## useQueryParam
66+
67+
You can use the `useQueryParam` hook to access the query params in current route. Pass in `undefined` to remove a query param from the url.
68+
69+
```js
70+
import { useQueryParam } from 'react-resource-router';
71+
72+
// Current route in address bar — /home/projects?foo=bar
73+
74+
export const MyComponent = () => {
75+
const [foo, setFoo] = useQueryParam('foo');
76+
// => foo will have the value 'bar'
77+
78+
const clickHandler = () => {
79+
setFoo('baz');
80+
// => Will update current route to /home/projects?foo=baz
81+
};
82+
83+
return (
84+
<div>
85+
<p>Hello World!</p>
86+
<button onClick={clickHandler}>Update param</button>
87+
</div>
88+
);
89+
};
90+
```
91+
92+
## usePathParam
93+
94+
You can use the `usePathParam` hook to access the path params in current route. Pass in `undefined` to remove an [optional param](https://github.com/pillarjs/path-to-regexp#optional) from the url.
95+
96+
```js
97+
import { usePathParam } from 'react-resource-router';
98+
99+
// path — /projects/:projectId/board/:boardId
100+
101+
// Current route in address bar — /projects/123/board/456?foo=bar
102+
103+
export const MyComponent = () => {
104+
const [projectId, setProjectId] = usePathParam('projectId');
105+
// => projectId will have the value '123'
106+
107+
const clickHandler = () => {
108+
setProjectId('222');
109+
// => Will update current route to /projects/222/board/456?foo=bar
110+
};
111+
112+
return (
113+
<div>
114+
<p>Hello World!</p>
115+
<button onClick={clickHandler}>Update param</button>
116+
</div>
117+
);
118+
};
119+
```

examples/basic-routing-with-resources/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html>
33
<head>
4-
<title>Example</title>
4+
<title>Example - Basic Routing with Resources</title>
55
</head>
66

77
<body>

examples/basic-routing/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!DOCTYPE html>
22
<html>
33
<head>
4-
<title>Example</title>
4+
<title>Example - Basic Routing</title>
55
</head>
66

77
<body>

examples/hooks/home.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from 'react';
2+
import { Link } from 'react-resource-router';
3+
4+
const baseURL = '/hooks';
5+
6+
const Home = () => {
7+
return (
8+
<div>
9+
<h1>Available Hooks</h1>
10+
<Link to={`${baseURL}/query-param?foo=abc&bar=xyz#abc`}>
11+
useQueryParam
12+
</Link>
13+
<br />
14+
<Link to={`${baseURL}/path-param/hello/world#abc?foo=abc&bar=xyz`}>
15+
usePathParam
16+
</Link>
17+
</div>
18+
);
19+
};
20+
21+
export default Home;

examples/hooks/index.html

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Example - Hooks</title>
5+
</head>
6+
7+
<body>
8+
<div id="root"></div>
9+
<script src="bundle.js" type="text/javascript"></script>
10+
</body>
11+
</html>

examples/hooks/index.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
4+
import {
5+
Router,
6+
RouteComponent,
7+
createBrowserHistory,
8+
} from 'react-resource-router';
9+
10+
import Home from './home';
11+
import QueryParamExample from './use-query-param';
12+
import PathParamExample from './use-path-param';
13+
14+
const myHistory = createBrowserHistory();
15+
16+
const baseURL = '/hooks';
17+
18+
const appRoutes = [
19+
{
20+
name: 'home',
21+
path: `${baseURL}`,
22+
exact: true,
23+
component: Home,
24+
navigation: null,
25+
},
26+
{
27+
name: 'query-param',
28+
path: `${baseURL}/query-param`,
29+
exact: true,
30+
component: QueryParamExample,
31+
navigation: null,
32+
},
33+
{
34+
name: 'path-param',
35+
path: `${baseURL}/path-param/:foo/:bar`,
36+
exact: true,
37+
component: PathParamExample,
38+
navigation: null,
39+
},
40+
];
41+
42+
const App = () => {
43+
return (
44+
<Router routes={appRoutes} history={myHistory}>
45+
<RouteComponent />
46+
</Router>
47+
);
48+
};
49+
50+
ReactDOM.render(<App />, document.getElementById('root'));

examples/hooks/use-path-param.tsx

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import React from 'react';
2+
import { Link, usePathParam } from 'react-resource-router';
3+
4+
const baseURL = '/hooks';
5+
6+
const randomStr = (length: number) => {
7+
let result = '';
8+
const characters = 'abcdefghijklmnopqrstuvwxyz';
9+
const charactersLength = characters.length;
10+
for (let i = 0; i < length; i++) {
11+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
12+
}
13+
14+
return result;
15+
};
16+
17+
const generateLightColorHex = () => {
18+
let color = '#';
19+
for (let i = 0; i < 3; i++)
20+
color += (
21+
'0' + Math.floor(((1 + Math.random()) * Math.pow(16, 2)) / 2).toString(16)
22+
).slice(-2);
23+
24+
return color;
25+
};
26+
27+
const UpdateButton = ({ for: paramKey = '' }) => {
28+
//eslint-disable-next-line
29+
const [param, setParam] = usePathParam(paramKey);
30+
31+
return (
32+
<div
33+
style={{
34+
margin: '20px 0',
35+
}}
36+
>
37+
<button onClick={() => setParam(randomStr(5))}>Update {paramKey}</button>
38+
</div>
39+
);
40+
};
41+
42+
const ComponentFoo = () => {
43+
// eslint-disable-next-line
44+
const [foo, setFoo] = usePathParam('foo');
45+
46+
return (
47+
<div
48+
style={{
49+
margin: '20px 0',
50+
padding: '20px',
51+
backgroundColor: generateLightColorHex(),
52+
}}
53+
>
54+
<div>
55+
I am ComponentFoo that consumes 'foo' query param. My background color
56+
changes on every render.
57+
</div>
58+
<p>foo={foo}</p>
59+
</div>
60+
);
61+
};
62+
63+
const ComponentBar = () => {
64+
// eslint-disable-next-line
65+
const [bar, setBar] = usePathParam('bar');
66+
67+
return (
68+
<div
69+
style={{
70+
margin: '20px 0',
71+
padding: '20px',
72+
backgroundColor: generateLightColorHex(),
73+
}}
74+
>
75+
<div>
76+
I am ComponentBar that consumes 'bar' query param. My background color
77+
changes on every render.
78+
</div>
79+
<p>bar={bar}</p>
80+
</div>
81+
);
82+
};
83+
84+
const PathParamExample = () => {
85+
return (
86+
<div>
87+
<h1>usePathParam - /hooks/use-path-param/:foo/:bar</h1>
88+
<ComponentFoo />
89+
<UpdateButton for={'foo'} />
90+
<ComponentBar />
91+
<UpdateButton for={'bar'} />
92+
<Link to={`${baseURL}`}>Go back to list of hooks</Link>
93+
</div>
94+
);
95+
};
96+
97+
export default PathParamExample;

examples/hooks/use-query-param.tsx

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import React from 'react';
2+
import { Link, useQueryParam } from 'react-resource-router';
3+
4+
const baseURL = '/hooks';
5+
6+
const randomStr = (length: number) => {
7+
let result = '';
8+
const characters = 'abcdefghijklmnopqrstuvwxyz';
9+
const charactersLength = characters.length;
10+
for (let i = 0; i < length; i++) {
11+
result += characters.charAt(Math.floor(Math.random() * charactersLength));
12+
}
13+
14+
return result;
15+
};
16+
17+
const generateLightColorHex = () => {
18+
let color = '#';
19+
for (let i = 0; i < 3; i++)
20+
color += (
21+
'0' + Math.floor(((1 + Math.random()) * Math.pow(16, 2)) / 2).toString(16)
22+
).slice(-2);
23+
24+
return color;
25+
};
26+
27+
const UpdateButton = ({ for: paramKey = '' }) => {
28+
//eslint-disable-next-line
29+
const [param, setParam] = useQueryParam(paramKey);
30+
31+
return (
32+
<div
33+
style={{
34+
margin: '20px 0',
35+
}}
36+
>
37+
<button onClick={() => setParam(randomStr(5))}>Update {paramKey}</button>
38+
<button onClick={() => setParam(undefined)}>Empty {paramKey}</button>
39+
</div>
40+
);
41+
};
42+
43+
const ComponentFoo = () => {
44+
// eslint-disable-next-line
45+
const [foo, setFoo] = useQueryParam('foo');
46+
47+
return (
48+
<div
49+
style={{
50+
margin: '20px 0',
51+
padding: '20px',
52+
backgroundColor: generateLightColorHex(),
53+
}}
54+
>
55+
<div>
56+
I am ComponentFoo that consumes 'foo' query param. My background color
57+
changes on every render.
58+
</div>
59+
<p>foo={foo}</p>
60+
</div>
61+
);
62+
};
63+
64+
const ComponentBar = () => {
65+
// eslint-disable-next-line
66+
const [bar, setBar] = useQueryParam('bar');
67+
68+
return (
69+
<div
70+
style={{
71+
margin: '20px 0',
72+
padding: '20px',
73+
backgroundColor: generateLightColorHex(),
74+
}}
75+
>
76+
<div>
77+
I am ComponentBar that consumes 'bar' query param. My background color
78+
changes on every render.
79+
</div>
80+
<p>bar={bar}</p>
81+
</div>
82+
);
83+
};
84+
85+
const QueryParamExample = () => {
86+
return (
87+
<div>
88+
<h1>useQueryParam</h1>
89+
<ComponentFoo />
90+
<UpdateButton for={'foo'} />
91+
<ComponentBar />
92+
<UpdateButton for={'bar'} />
93+
<Link to={`${baseURL}`}>Go back to list of hooks</Link>
94+
</div>
95+
);
96+
};
97+
98+
export default QueryParamExample;

0 commit comments

Comments
 (0)