根据Reaction的文档,useRef()表示当您需要不影响呈现的数据时,为了将引用传递给子组件,您必须对子组件使用forwardRef包装器.

我正在使用Reaction和TypeScrip,在try 将引用传递给我的子组件时遇到了一个问题.我遇到的问题是,子组件中的ref类型是((instance: T | null) => void) | MutableRefObject<T | null> | null;,这并没有提供如何提取ref的值的清晰方法.

示例:


function ParentComponent() {
  const someData = useRef(1);
  // some event handling who may change the value of someData
  return (
    <ChildComponent ref={someData} />
 );
}


const ChildComponent = forwardRef<number>(function ChildComponent(props, ref) {
  function onClick() {
    // use ref here, need the number from ref but get type error
  }

  return <button onclick={onClick} type="button"></button>;
}

虽然我理解ref的主要用例是处理用于操作的DOM引用,但ref的核心目的是包含在更改时不应影响呈现的数据.

有没有其他方法来传递数据而不影响呈现到子组件,这是不应该做的事情,或者我只需要将其强制转换为MutableRefObject<T | null> | null并到此为止?我担心类型上的函数签名,如果我需要做任何事情的话.我在搜索过程中找到的所有内容都只涉及在两者之间传递DOM引用,而不是实际的数据.

推荐答案

正如你所指出的,ref可以是不同类型的,所以TypeScrip不知道该建议什么.可以是((instance: T | null) => void),也可以是MutableRefObject<T | null>null. 这将是提取其价值的一种方式:

  function onClick() {
    let extracted: number | null=null;
    if (ref) { // TypeScript infers it's not null inside the clause
      if (typeof ref === 'function') { // TypeScript infers it's a function
        ref(1); // not sure what that actually does, I guess it's a setter when you pass a "callback" with ref = React.createRef()
      } else { // TypeScript infers there's only one possibily left: it has the "current" property.
        extracted = ref.current;
      }
    }
    console.log(extracted)
  }

既然你已经控制了ChildCompoent米,你其实并不需要把它包起来.您只需go 除forwardRef的魔力,并将someData作为常规对象传递,即可进行如下处理:

function ParentComponent()=> {
    const someData = useRef(1);
    console.log("rendering parent")
    useEffect(() => {
        const timer = setTimeout(() => {
            someData.current = 2
        }, 1000);
        return () => clearTimeout(timer);
    }, [])
    return (
        <ChildComponent someData={someData}/>
    );
}


function ChildComponent(ref: { someData: MutableRefObject<number> }) {
    function onClick() {
        console.log("clicked with no:", ref.someData.current)
    }

    console.log("rendering child")
    return <button onClick={onClick} type='button'></button>;
}

将记录

rendering parent // might be appear twice but only b/c you run it in dev environment
rendering child // as above
clicked with no: 1 // if you're fast enough
clicked with no: 2 

useRef背后的整个思想是,您只是传递一个对值的引用(例如someData.current),因此可以在引擎不注意到组件更新(b/c someData仍然是相同的对象)的情况下操作它,因此不需要启动重现器.既然没有更多的东西,你可以用任何你喜欢的方式传递它.

Typescript相关问答推荐

如何将绑定到实例的类方法复制到类型脚本中的普通对象?

有没有可能使用redux工具包的中间件同时监听状态的变化和操作

在泛型类型中对子代执行递归时出错

如何将类型从变量参数转换为返回中的不同形状?

泛型函数即使没有提供类型

创建一个根据布尔参数返回类型的异步函数

如何在TypeScript中将一个元组映射(转换)到另一个元组?

ANGLE找不到辅助‘路由出口’的路由路径

路由链接始终返回到

有没有可能产生输出T,它在视觉上省略了T中的一些键?

编译TypeScrip项目的一部分导致错误

根据类型脚本中的泛型属性 Select 类型

跟踪深度路径时按条件提取嵌套类型

->;Boolean类型的键不能分配给类型Never

在组件卸载时try 使用useEffect清除状态时发生冲突.react +打字

如何在本地存储中声明该类型?

TypeScrip:从嵌套的对象值创建新类型

为什么 Typescript 无法正确推断数组元素的类型?

React 中如何比较两个对象数组并获取不同的值?

通用可选函数参数返回类型