我可以在全局范围内声明 Ref 以从其范围之外的函数操作组件吗?

Can I declare Ref at the global scope to manipulate a component from a function outside its scope?

我想要一个自定义挂钩,它可以为我提供一个 ScrollView 组件和一个命令式控制该给定组件滚动的函数。

我正在使用一个名为 react-native-keyboard-aware-scroll-view, which allows me to catch the reference of the component trough a prop called innerRef. Through that reference I have access to a series of methods 的库,我可以用它来操纵滚动。

我发现该“控制函数”在 ScrollView 组件范围之外访问引用的唯一方法是使用 [=15] 在全局范围内创建 ref =] 如下所示:

const ref = createRef();

const ScrollView = ({ children, ...props }) => {
  return (
    <KeyboardAwareScrollView
      {...props}
      innerRef={(inner) => {
        ref.current = inner; //adding ref to scrollview
      }}
    >
      {children}
    </KeyboardAwareScrollView>
  );
};

const useScrollTo = () => {

  const scrollTo = (position) => {
    if (ref.current && position) {

     /* controlling scroll using ref */
      ref.current.scrollTo({
        x: 0,
        y: position,
        animate: true
      });
    }
  };

  return { ScrollView, scrollTo };
};

export default useScrollTo;

即使 const 在全局范围内的声明创建的全局变量不是全局对象的一部分,但我觉得它是反模式的,所以我想知道是否有适合我的方法这样做不需要像这样在全局范围内有一个 ref。这可能吗?

编辑

这里有一个 example 这个挂钩用于协助对长表单进行表单验证,将用户指向未能通过验证的输入:

感谢您提供的工作示例,这就是我管理场景的方式: https://codesandbox.io/s/frosty-sea-83tvx6?file=/src/ScrollView.js

自定义钩子现在是一个真正的钩子,因为它使用了反应钩子:

const useScrollTo = () => {
  const ref = useRef();

  const scrollTo = (position) => {
    if (ref.current && position) {
      ref.current.scrollTo({
        x: 0,
        y: position,
        animate: true
      });
    }
  };

  return {
    ref,
    scrollTo,
    ScrollView

  };
};

引用在挂钩中创建,由您的 App 组件检索并传递给您的 ScrollComponent:

function App() {
  const { ref, scrollTo, ScrollView } = useScrollTo();
  const [position, setPosition] = useState(0);
  const [errorPresent, setErrorPresent] = useState(false);

  const simulateValidation = () => {
    scrollTo(position);
    setErrorPresent(true);
  };

  return (
    <ScrollView myRef={ref}>
    ...
    ...

您的 ScrollView 组件:

const ScrollView = ({ children, myRef, ...props }) => {
  return (
    <KeyboardAwareScrollView
      {...props}
      innerRef={(inner) => {
        myRef.current = inner;
      }}
    >
      {children}
    </KeyboardAwareScrollView>
  );
};

为了简单起见,我没有使用 React.forwardRef 包装器,如果您不喜欢必须命名 refs 的想法,您可以将 ScrollView 包装在 React.forwardRef() 中并传递 ref <ScrollView ref={ref}>.

编辑:我通过从钩子中返回 ScrollView 组件来更新示例,尽管我个人不喜欢这种做法,但我知道有些人喜欢使用它来避免在他们的组件中导入重复模块.