如何将 React Router 参数与状态同步

bar*_*iro 5 reactjs react-router-dom react-hooks

使用 React Router Web。

假设我们有一条路线:/:user?showDetails=true。我们知道如何使用钩子和类似自定义钩子的东西从 URL获取数据。useParamsuseQuery

此外,我们知道如何使用来设置这些数据history.push(/baruchiro?showDetails=false)

但是,如果我们获取并设置此数据,并且万一我们不使用它来将用户从一个页面重定向到另一个页面,而是更改当前组件(让用户保存其当前页面视图),则意味着路线状态

如何使用路由作为状态而不用大量的history.pushand弄脏组件useParams

bar*_*iro 6

更新

我将此自定义挂钩发布为npm 包use-route-as-state


如果你想使用routeas state,你需要一种方法来获取路由参数,并更新它们。

你无法避免使用,history.push因为这是你改变你的“状态”,你的route. 但您可以隐藏此命令以获得更清晰的代码。

以下是如何在自定义挂钩中隐藏getupdate的示例,使它们看起来像常规useState挂钩:

使用查询参数作为状态:

import { useHistory, useLocation} from 'react-router-dom'

const useQueryAsState = () => {
    const { pathname, search } = useLocation()
    const history = useHistory()

    // helper method to create an object from URLSearchParams
    const params = getQueryParamsAsObject(search)

    const updateQuery = (updatedParams) => {
        Object.assign(params, updatedParams)
        // helper method to convert {key1:value,k:v} to '?key1=value&k=v'
        history.replace(pathname + objectToQueryParams(params))
    }

    return [params, updateQuery]
}
Run Code Online (Sandbox Code Playgroud)

使用路由参数作为状态:

import { generatePath, useHistory, useRouteMatch } from 'react-router-dom'

const useParamsAsState = () => {
    const { path, params } = useRouteMatch()
    const history = useHistory()

    const updateParams = (updatedParams) => {
        Object.assign(params, updatedParams)
        history.push(generatePath(path, params))
    }
    return [params, updateParams]
}
Run Code Online (Sandbox Code Playgroud)

请注意查询参数history.replace代码中的和路由参数代码中的。history.push

用法:(不是我的代码中的真正组件,如果存在编译问题,抱歉)

const ExampleComponent = () => {
    const [{ user }, updateParams] = useParamsAsState()
    const [{ showDetails }, updateQuery] = useQueryAsState()

    return <div>
        {user}<br/ >{showDetails === 'true' && 'Some details'}
        <DropDown ... onSelect={(selected) => updateParams({ user: selected }) />
        <Checkbox ... onChange={(isChecked) => updateQuery({ showDetails: isChecked} })} />
    </div>
}
Run Code Online (Sandbox Code Playgroud)