渲染 React 组件后如何滚动到视图中?

问题描述 投票:0回答:1

我正在尝试将视图滚动到特定组件。我正在使用 refs 来跟踪组件,并且尝试调用scrollIntoView 函数来移动到特定的引用。我遇到的问题是,当我尝试将对scrollIntoView 的调用置于useEffect 内部时,没有任何反应。该命令在鼠标单击时起作用,很可能是因为该组件已经渲染到屏幕上。

这是我的代码:

import React, { forwardRef, useEffect, useRef} from 'react';
import { Box, Button, Grid, Stack} from '@mui/material';

const component_1 = 'Component 1';
const component_2 = 'Component 2';
const component_3 = 'Component 3';
const component_4 = 'Component 4';
const component_5 = 'Component 5';
const component_6 = 'Component 6';
const component_7 = 'Component 7';
const component_8 = 'Component 8';
const component_9 = 'Component 9';
const component_10 = 'Component 10';

export const RefLabel = forwardRef((props, ref) => {
    const { label } = props;
    return <div ref={ref}>{label}</div>;
});

export const TheComponent = (props) => {

    const sectionRefs = {
        [component_1]: useRef(),
        [component_2]: useRef()
        [component_3]: useRef()
        [component_4]: useRef()
        [component_5]: useRef()
        [component_6]: useRef()
        [component_7]: useRef()
        [component_8]: useRef()
        [component_9]: useRef()
        [component_10]: useRef()
    }
    const navToSection = (section) => {
        sectionRefs[section].current?.scrollIntoView({ behavior: 'smooth' });
    };
    useEffect(() => {
        //This does not work. The useEffect is called but the scrolling does not happen  
        navToSection(component_9);
    }, []);
    return (
        <Grid container>
            <Stack>
                <Box>
                    <Button onClick={()=>{navToSection(component_9)}>Go to 9</Button>
                    <RefLabel ref=sectionRefs[component_1] label='label 1'>
                    <RefLabel ref=sectionRefs[component_2] label='label 2'>
                    <RefLabel ref=sectionRefs[component_3] label='label 3'>
                    <RefLabel ref=sectionRefs[component_4] label='label 4'>
                    <RefLabel ref=sectionRefs[component_5] label='label 5'>
                    <RefLabel ref=sectionRefs[component_6] label='label 6'>
                    <RefLabel ref=sectionRefs[component_7] label='label 7'>
                    <RefLabel ref=sectionRefs[component_8] label='label 8'>
                    <RefLabel ref=sectionRefs[component_9] label='label 9'>
                    <RefLabel ref=sectionRefs[component_10] label='label 10'>
                </Box>
            </Stack>
        </Grid>

在此代码中,useEffect 根本不滚动。但是,当按下顶部按钮时,滚动视图会正确滚动到正确的参考标签。

还应该注意的是,此代码在浏览器滚动条内创建了一个滚动面板。无论如何,在组件完全渲染后从事件调用时,scrollIntoView 会起作用。我需要的是一种在渲染后自动滚动到组件的方法。在线文档建议将滚动逻辑放在 useEffect 中,但这对我不起作用。 (例如:https://www.codemzy.com/blog/react-scroll-to-element-on-render

还要注意,这段代码是从真实代码中抽象出来的,这就是为什么它会做一些奇怪的事情,比如创建 10 个组件。真实的代码有一个内部滚动条,并且 RefLabels 包含在滚动窗格中。所有参考标签在滚动到可以显示的位置之前都是不可见的。

javascript html reactjs react-hooks material-ui
1个回答
0
投票

您没有在加载时滚动的原因有几个:

  1. A
    ref
    的初始值为 null(除非您自己传递初始值),并且直到第一次渲染之后才会将其值更新到 DOM 对象
  2. useEffect
    将在 before 第一次渲染之前运行,并且由于您指定了一个空的依赖项数组,所以这是它唯一运行的时间。

如果您需要在渲染后立即访问元素,则一种常见模式是传递

ref
的回调而不是 ref 对象,并将元素存储在状态中。现在,您的 useEfect 可以依赖于状态片段,并在值更改后运行代码。您可能需要重新考虑一些逻辑才能将其适合您的用例,但这是我正在谈论的示例:

代码沙箱链接:https://codesandbox.io/p/sandbox/scroll-react-question-2t2hny

import { useState, useEffect } from "react";

export default function App() {
  const [element, setElement] = useState(undefined);

  useEffect(() => {
    if (element) {
      element.scrollIntoView();
    }
  }, [element]);

  return (
    <div>
      <div style={{ height: "200vh" }}>
        Big element to push the scroll element outside of view
      </div>
      <div ref={setElement}>Scroll element</div>
    </div>
  );
}

在上面的代码中,useEffect会运行两次。渲染之前一次(当元素状态仍未定义时。然后当元素状态更改为 DOM 对象时再一次。

© www.soinside.com 2019 - 2024. All rights reserved.