使用 TypeScript React Refs:无法读取未定义的属性“当前”

J. *_*ers 6 forward-reference typescript reactjs react-ref

我正在使用 TypeScript 构建 React 应用程序。

我想创建按钮,滚动到主页上子组件的标题。

我已经在子组件中创建了一个引用,遵循此堆栈溢出答案,并(尝试)使用前向引用在我的父组件上访问它。

export class Parent extends Component {
  private testTitleRef!: RefObject<HTMLHeadingElement>;

  scrollToTestTitleRef = () => {
    if (this.testTitleRef.current !== null) {
      window.scrollTo({
        behavior: "smooth",
        top: this.testTitleRef.current.offsetTop
      });
    }
  };

  render() {
    return <Child ref={this.testTitleRef} />
  }
}

interface Props {
  ref: RefObject<HTMLHeadingElement>;
}

export class Child extends Component<Props> {
  render() {
    return <h1 ref={this.props.ref}>Header<h1 />
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我触发时,scrollToTestTitleRef我收到错误:

Cannot read property 'current' of undefined
Run Code Online (Sandbox Code Playgroud)

这意味着 ref 未定义。这是为什么?我究竟做错了什么?

编辑: Estus帮助我创建了参考。但是当我触发scrollToTestTitleRef()事件时,它不会滚动。当console.log this.testTitleRef.current我得到输出时:

{"props":{},"context":{},"refs":{},"updater":{},"jss":{"id":1,"version":"9.8.7","plugins":{"hooks":{"onCreateRule":[null,null,null,null,null,null,null,null,null,null,null,null],"onProcessRule":[null,null,null],"onProcessStyle":[null,null,null,null,null,null],"onProcessSheet":[],"onChangeValue":[null,null,null],"onUpdate":[null]}},"options":{"plugins":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}]}},"sheetsManager":{},"unsubscribeId":null,"stylesCreatorSaved":{"options":{"index":-99999999945},"themingEnabled":false},"sheetOptions":{},"theme":{},"_reactInternalInstance":{},"__reactInternalMemoizedUnmaskedChildContext":{"store":{},"storeSubscription":null},"state":null}
Run Code Online (Sandbox Code Playgroud)

注意:cacheClasses我删除了、_reactInternalFiber和 的键__reactInternalMemoizedMaskedChildContext,因为它们包含循环依赖关系。

所以当前似乎没有 的密钥offsetTop。这可能与以下事实有关:在我的实际应用程序中,子组件被包装在material-ui'swithStyle和React-Redux'内connect

Est*_*ask 3

!非空断言运算符抑制了实际问题。JavaScript/TypeScript 中无法testTitleRef将属性分配为<Child ref={this.titleRef} />,因此它保持未定义状态(与testTitleRef和也存在不一致titleRef)。

它应该是这样的:

  private testTitleRef: React.createRef<HTMLHeadingElement>();

  scrollToTestTitleRef = () => {
      if (!this.testTitleRef.current) return;

      window.scrollTo({
        behavior: "smooth",
        top: this.testTitleRef.current.getBoundingClientRect().top + window.scrollY
      });
  };
  render() {
    return <Child scrollRef={this.testTitleRef} />
  }
Run Code Online (Sandbox Code Playgroud)

export class Child extends Component<Props> {
  render() {
    return <h1 ref={this.props.scrollRef}>Header<h1 />
  }
}
Run Code Online (Sandbox Code Playgroud)