初学者,但发现这很棘手。因此,我们将不胜感激!
我想让用户过滤一些选项。这些过滤器应该反映在 URL 中。例如:
http://localhost:3000/items?counter=1
现在,当用户访问
http://localhost:3000/items?counter=2
时,我希望将其反映在状态中并将其放入状态中。如果同一用户以某种方式更改状态,我希望将其反映在 url 中。我确实知道如何做这两件事。
但我觉得我在这里陷入了无限循环:
useEffect(() => {
router.push(`/items?counter=${counter}`, undefined, { shallow: true })
}, [counter])
useEffect(() => {
setCounter(parseInt(router.query.counter))
}, [router.query.counter])
我如何才能最好地从查询参数中获取状态,同时在每次状态更改时始终浅层更新查询参数?
始终只更新其中一个,并通过监听第一个的变化来更新另一个。由于状态始终源自查询,因此我会通过
useEffect
更新状态,并始终直接更改查询。
这意味着您不直接更新状态。每当你想要更新状态时,你都需要更新查询:
const updateCounterQuery = currentCounter => router.push(`/items?counter=${currentCounter}`, undefined, { shallow: true })
useEffect(() => {
setCounter(parseInt(router.query.counter))
}, [router.query.counter])
但是,为什么在这种情况下还需要一个状态呢?始终使用从查询中获得的值:
const updateCounterQuery = counter => router.push(`/items?counter=${counter }`, undefined, { shallow: true })
const counter = +router.query.counter
对于需要多个查询字符串(例如
?counter=2&filter=true
)或同时更新(例如?latitude=47.367&longitude=8.543
)的更复杂的用例,将逻辑抽象为钩子通常是有意义的。
像next-usequerystate这样的库正好解决了这个用例。 this 或 this 等指南和示例是自定义开发的良好切入点。
更容易使用库来字符串化/解析参数,我创建了一个 https://github.com/asmyshlyaev177/state-in-url
如果不小心,useEffect
可能会形成循环。像这样应该可以解决问题:
const { state, updateState, updateUrl } = useUrlState(form);
const timer = React.useRef(0 as unknown as NodeJS.Timeout);
React.useEffect(() => {
clearTimeout(timer.current);
timer.current = setTimeout(() => {
// using JSON.stringify internally to compare state and do router.push only if values are different
updateUrl(state);
}, 500);
return () => {
clearTimeout(timer.current);
};
}, [state, updateUrl]);