我在页面上有一个实时过滤器结构。来自输入的数据既保留在我的州,也保留为URL查询,以便当有人打开带有URL中的过滤器的页面时,已经选择了正确的过滤器。
我正在努力寻找一种稳定的方法来使这2个保持同步。目前,我是在加载时从URL中获取数据,并在更改状态时在URL中设置数据,但是这种结构实际上使得无法重用所涉及的组件,并且错误很容易导致无限循环,这实际上也是无法扩展。有没有更好的架构来处理这些同步?
答案 0 :(得分:2)
我建议从查询参数管理视图中过滤器的状态。如果使用react-router,则可以使用查询参数代替状态,并且在render方法中获取视图元素所需的参数。更改过滤器后,您需要实现重定向。为了更加方便,最好使用qs module。使用这种方法,您还将收到一个现成的参数,用于请求后端。
示例容器:
const initRequestFields = {someFilterByDefault: ''};
class Example extends Component{
constructor(props) {
super(props);
this.lastSearch = '';
}
componentDidMount() {
this.checkQuery();
}
componentDidUpdate() {
this.checkQuery();
}
checkQuery() {
const {location: {search}, history} = this.props;
if (search) {
this.getData();
} else {
history.replace({path: '/some-route', search: qs.stringify(initRequestFields)});
}
}
getData() {
const {actionGetData, location: {search}} = this.props;
const queryString = search || `?${qs.stringify(initRequestFields)}`;
if (this.lastSearch !== queryString) {
this.lastSearch = queryString;
actionGetData(queryString);
}
}
onChangeFilters = (values) => {
const {history} = this.props;
history.push({path: '/some-route', search: qs.stringify(values)});
};
render() {
const {location: {search}} = this.props;
render(<Filters values={qs.parse(search)} onChangeFilers={this.onChangeFilters} />)
}
}
此逻辑最好保存在将值传递给组件的最高容器中。
有关更多信息,请访问
Query parameters in react router
答案 1 :(得分:0)
此答案使用了反应钩子
您想使URL
与state
保持同步,需要从URL
到state
(组件安装时)和{ state
到URL
(更新过滤器时)。
使用反应路由器挂钩,您可以使用URL
获取反应性对象,并将其用作state
,这是一种方法-从URL
到组件。
相反的方法-更改组件后更新URL
,可以使用history.replace
。
您可以在自定义钩子中隐藏这两种方式,它的工作方式类似于常规的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]
}
要将路由参数用作状态:
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]
}
请注意查询参数代码中的
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>
}
我将此自定义钩子发布为 npm包 :use-route-as-state