业务背景
B 端后台系统中常见的业务场景就是表单列表页面,当用户A浏览第三页表单时,通过 url 分享给用户B后希望B用户打开链接后页面和用户A看到的数据一致。这就需要将页面url参数解析并赋值到组件内状态,并且组件内部的状态更改后同步到url中(以便二次分享)。
解决方案
使用浏览器的原生 window.location
和 URLSearchParams
来实现这个功能。以下是一个示例,展示如何手动控制 URL 和组件状态的双向绑定,以实现分页功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| import React, { useState, useEffect } from 'react';
function useQuery() { return new URLSearchParams(window.location.search); }
function MyComponent() { const query = useQuery();
const [pageNum, setPageNum] = useState(Number(query.get('pageNum')) || 1); const [pageSize, setPageSize] = useState(Number(query.get('pageSize')) || 10);
useEffect(() => { const params = new URLSearchParams(window.location.search); if (pageNum) { params.set('pageNum', pageNum); } if (pageSize) { params.set('pageSize', pageSize); } window.history.replaceState(null, '', '?' + params.toString()); }, [pageNum, pageSize]);
const handlePageChange = (newPageNum) => { setPageNum(newPageNum); };
const handlePageSizeChange = (newPageSize) => { setPageSize(newPageSize); };
return ( <div> <h1>分页组件</h1> <p>Page Number: {pageNum}</p> <p>Page Size: {pageSize}</p> <button onClick={() => handlePageChange(pageNum + 1)}>Next Page</button> <button onClick={() => handlePageSizeChange(20)}>Set Page Size to 20</button> </div> ); }
export default MyComponent;
|
通过上面这种方式,可以实现 URL 参数和组件状态的双向绑定,使得分页信息可以在 URL 和组件状态之间保持同步。
如果每个页面都这样手控控制就会造成大量冗余代码,可以抽离成通用 hook, 这样其他组件使用时可以直接命名参数名、参数值。
抽离通用 hook:useSyncedQueryParam
以下是实现方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import { useState, useEffect } from 'react';
function useQueryParams() { return new URLSearchParams(window.location.search); }
function useSyncedQueryParam(paramName, defaultValue) { const query = useQueryParams(); const [value, setValue] = useState(query.get(paramName) || defaultValue);
useEffect(() => { const params = new URLSearchParams(window.location.search); if (value !== undefined && value !== null) { params.set(paramName, value); } else { params.delete(paramName); } window.history.replaceState(null, '', '?' + params.toString()); }, [value, paramName]);
return [value, setValue]; }
export default useSyncedQueryParam;
|
可以在组件中使用这个通用 Hook,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| import React from 'react'; import useSyncedQueryParam from './useSyncedQueryParam';
function MyComponent() { const [pageNum, setPageNum] = useSyncedQueryParam('pageNum', 1); const [pageSize, setPageSize] = useSyncedQueryParam('pageSize', 10);
const handlePageChange = (newPageNum) => { setPageNum(newPageNum); };
const handlePageSizeChange = (newPageSize) => { setPageSize(newPageSize); };
return ( <div> <h1>分页组件</h1> <p>Page Number: {pageNum}</p> <p>Page Size: {pageSize}</p> <button onClick={() => handlePageChange(pageNum + 1)}>Next Page</button> <button onClick={() => handlePageSizeChange(20)}>Set Page Size to 20</button> </div> ); }
export default MyComponent;
|
这样就可以在多个组件中复用 useSyncedQueryParam
Hook,轻松实现 URL 参数和组件状态的双向绑定。