Если вы хотите, чтобы useEffect()
реагировал только на изменение selectedArticle
, используйте isDesktop
и selectedArticle
для инициализации состояний компонентов. Всякий раз, когда selectedArticle
изменяется, первый useEffect()
обновляет оба состояния переданными реквизитами и запускает второй useEffect()
для повторного запуска при следующем рендеринге.
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
const [desktop, setDesktop] = useState(isDesktop)
const [article, setArticle] = useState(selectedArticle)
useEffect(() => {
if (article !== selectedArticle) {
setDesktop(isDesktop)
setArticle(selectedArticle)
}
}, [isDesktop, selectedArticle, article])
useEffect(() => {
if (desktop) scrollToTop()
else scrollToTopOfArticle()
}, [desktop, article])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
)
}
В качестве альтернативы выможет абстрагировать это поведение фиксации к другому хуку, так что isDesktop
обновляется до своего действительного значения только при изменении selectedArticle
. Обратите внимание, что selectedArticle
по-прежнему должен зависеть от эффекта действия прокрутки, поэтому useEffect()
будет запускать действие прокрутки при каждом изменении на selectedArticle
, даже если isDesktop
не изменило значения с момента последнего запуска.
const useLatch = (value, deps) => {
const [state, setState] = useState(value)
const effect = useCallback(() => { setState(value) }, [value])
useEffect(effect, deps)
return state
}
const scrollToTop = () => window.scrollTo(0, 0)
const scrollToTopOfArticle = () => window.scrollTo(0, 200)
function App({
isDesktop,
selectedArticle
}) {
const latchedIsDesktop = useLatch(isDesktop, [selectedArticle])
useEffect(() => {
if (latchedIsDesktop) scrollToTop()
else scrollToTopOfArticle()
}, [latchedIsDesktop, selectedArticle])
return (
<div className="App">
<h1>{selectedArticle.title}</h1>
<p>{selectedArticle.body}</p>
</div>
)
}