在渲染时将滚动反应到顶部——通常的答案似乎不起作用
Posted
技术标签:
【中文标题】在渲染时将滚动反应到顶部——通常的答案似乎不起作用【英文标题】:React scroll to top on render--the usual answer doesn't seem to be working 【发布时间】:2022-01-03 02:03:43 【问题描述】:我有一个带有左侧导航栏的 React 应用程序,然后页面在右侧呈现。当我在右侧查看页面并向下滚动然后使用导航栏转到另一个页面时,新页面将呈现与前一页相同的滚动位置。我希望新页面始终滚动到顶部。
这几天我做了很多阅读,每个人似乎都同意解决方案是使用useEffect
,如下所示:
const location = useLocation();
useEffect(() =>
window.scrollTo(0, 0);
, [location]);
这很有意义,而且我从调试中知道,只要 URL 发生变化,效果就会按预期运行。问题是调试似乎表明效果是在页面呈现在屏幕上之前运行的。 (我一步步调试:绘制左侧导航,运行效果,然后绘制页面。这对我来说毫无意义,因为效果是在绘制页面的组件中定义的,据我了解,@ 987654323@ 应该在页面渲染之后发生。)
这里有一些打字稿代码,希望它能帮助识别我的问题:
侧边栏:
interface Props<T extends Stuff>
children: React.ReactNode | React.ReactNode[];
stuff:
[key: string]: T;
;
title: string;
type: 'arf' | 'create' | 'edit';
handleBackClick: () => void;
const MySidebar = <T extends Stuff>(
children,
stuff,
title,
type,
handleBackClick,
: Props<T>) => (
<Box
position="relative"
zIndex="1"
overflow="auto"
>
<Flex
as="aside"
width=['100%', '100%', '300px']
left="0px"
top="0px"
position="fixed"
height= base: 'auto', md: '100%'
backgroundImage=[
`url($BackgroundImage)`,
`url($BackgroundImage)`,
'none',
]
backgroundColor=['transparent', 'transparent', 'white']
padding= base: '0px', md: '0px 20px 0px 20px'
flexDir="column"
zIndex=9
overflow="auto"
>
<Box
flexGrow=1
display="flex"
flexDir="column"
backgroundColor=['transparent', 'transparent', 'white']
>
<Flex
textAlign="center"
my=['30px', '30px', '75px']
justifyContent="center"
minHeight="31px"
>
<Box display=['none', 'none', 'block']>
<Link to=PrivateRoutes.A_PRIVAE_ROUTE>
<Image src=DesktopLogoIcon />
</Link>
</Box>
</Flex>
<Text
as="p"
mb="18px"
fontSize="xs"
textAlign= base: 'center', md: 'left'
>
<b>title</b>
</Text>
<Flex
flexDir= base: 'row', md: 'column'
px= base: '30px', md: '0px'
as="ul"
overflowX=['scroll', 'scroll', 'hidden']
listStyleType="none"
>
Object.keys(stuff).map((thingName) =>
const thing = stuff[thingName as keyof typeof stuff] as Stuff;
return (
<li key=`$thing.route-$thing.text`>
<NavLinkWrapperInEntry
to=thing.route
activeStyle=
type === 'edit'
?
backgroundColor: 'white',
color: 'black',
:
>
thing.completed && type !== 'arf' && (
<Image
src=CircleCheckIcon
minWidth="16px"
mr="6px"
/>
)
thing.text
</NavLinkWrapperInEntry>
</li>
);
)
</Flex>
</Box>
type !== 'arf' ? (
<Button
buttonColor="black"
display= base: 'none', md: 'block'
onClick=handleBackClick
mb="8px"
>
Back to dashboard
</Button>
) : (
<>
<Button
buttonColor="black"
display= base: 'none', md: 'block'
mb="8px"
type="submit"
form="arf_form"
>
Save & Exit
</Button>
<ButtonLink
textDecor="underline"
onClick=handleBackClick
mb="20px"
>
Back to Dashboard
</ButtonLink>
</>
)
</Flex>
<MyPage type=type>
children
</MyPage>
</Box>
);
export default MySidebar;
type MyPageProps =
type: string;
children: React.ReactNode | React.ReactNode[];
const MyPage: React.FC<MyPageProps> = ( type, children ) =>
const location = useLocation();
useEffect(() =>
window.scrollTo(0, 0);
, [location]);
return (
<Box
width=['100%', '100%', 'calc(100% - 300px)']
marginLeft=['0px', '0px', '300px']
backgroundImage=`url($BackgroundImage)`
padding= base: '200px 0px 20px 0px', md: '100px 20px 20px 20px'
as='main'
display='flex'
flexDir='column'
alignItems='center'
position='relative'
backgroundRepeat='none'
backgroundSize='cover'
>
location.pathname !== PrivateRoutes.ARF_ARF && type === 'arf' && (
<ArfArfArf />
)
<Box maxWidth='900px' width='100%'>
children
</Box>
</Box>
);
export default MyPage;
ArfArfArf:
const ArfArfArf: React.FC = () =>
return (
<Box
backgroundColor="black"
p="15px"
color="white"
textAlign="center"
maxWidth="900px"
mb="28px"
>
<h2>
<b>
Some text we want displayed on almost every page
</b>
</h2>
</Box>
);
;
export default ArfArfArf;
在 MyPage 上呈现的典型子项是带有 id="arf_form"
的冗长表单。如果需要,我可以包含一个示例,但如果没有必要,我不想用代码完全压倒每个人。
我们确实使用了 react-router,我的研究表明,与其将 useEffect
直接放在我的组件中,不如通过创建 ScrollToTop 组件来提供更好的服务:
type ScrollToTopProps =
children?: React.ReactNode | React.ReactNode[];
const ScrollToTop: React.FC<ScrollToTopProps> = ( children ) =>
const location = useLocation();
useEffect(() =>
window.scrollTo(0, 0);
, [location]);
return <>children</>
;
export default ScrollToTop;
我已经尝试将它插入到我的组件树的各个级别中,它似乎与将它放在我在代码中显示它的位置(在 MyPage 中)具有完全相同的效果——效果运行,但在页面之前视觉呈现,然后页面在上一页的滚动位置呈现。
这整件事让我很困惑,因为几乎我看过的每个地方都给出了相同的解决方案,而且无论出于何种原因,这个解决方案显然在这种情况下不起作用。我愿意接受任何建议。
【问题讨论】:
认为您可以创建一个 running 代码框来重现我们可以实时检查和调试的问题? @DrewReese 我会试一试,但我主要是一个后端开发人员,最近把一个 React 前端丢在他的腿上,所以我真的不知道我在做什么做,TBH。 @DrewReese 以防万一你想知道,我还没有放弃给你一个运行的代码框。我一直在不停地工作;问题是我无法让它重现我的问题。滚动到顶部的通常修复方法在代码框中工作得很好,无论我做什么尝试破坏它。 别担心....如果你能得到一个,你可以像刚才一样在这里 ping(对我)。 【参考方案1】:也许我错了,但我认为您不应将窗口滚动到顶部,而应将某些元素滚动到顶部。 也许这会有所帮助: Set textarea scroll from ReactJS state
【讨论】:
这似乎是个好主意,所以我尽力在MyPage
组件中实现它。我将 useLocation
和 useEffect
代码替换为 ``` const mainRef = useRefref=mainRef
。不幸的是,它没有帮助。以上是关于在渲染时将滚动反应到顶部——通常的答案似乎不起作用的主要内容,如果未能解决你的问题,请参考以下文章