React 中需要操作元素时,可通过 findDOMNode() 或通过 createRef() 创建对元素的引用来实现。前者官方不推荐,所以这里讨论后者及其与 TypeScript 结合时如何工作。
React 中的元素引用正常的组件中,可通过创建对元素的引用来获取到某元素然后进行相应操作。比如元素加载后将焦点定位到输入框。 class App extends Component { constructor(props){ super(props); this.inputRef = React.createRef(); } componentDidMount(){ this.inputRef.current.focus() } render() { return ( <div className="App"> <input type="text" ref={this.inputRef}/> </div> ); } } 创建对元素的引用是通过 React 内部对引用的 if(this.inputRef.current){ this.inputRef.current.focus() } 在上面的示例中,之所以不用判空是因为我们在 组件中引用的传递对于原生 DOM 元素可以像上面那样创建引用,但对于自己写的组件,则需要使用 假如你写了个按钮组件,想要实现像上面那样,让使用者可通过传递一个 button.jsx const FancyInput = props => <input type="text" className="fancy-input" />; 添加 ref 支持后的按钮组件: button.jsx const FancyInput = React.forwardRef((props, ref) => { return <input type="text" ref={ref} className="fancy-input" />; });
使用上面创建的 class App extends Component { constructor(props) { super(props); this.inputRef = React.createRef(); } componentDidMount() { if (this.inputRef.current) { this.inputRef.current.focus(); } } render() { return ( <div className="App"> - <input type="text" ref={this.inputRef}/> + <FancyInput ref={this.inputRef} /> </div> ); } } TypeScript 中传递引用先看正常情况下,对原生 DOM 元素的引用。还是上面的示例: class App extends Component<{}, {}> { private inputRef = React.createRef(); componentDidMount() { /** ?? Object is possibly ‘null‘ */ this.inputRef.current.focus(); } render() { return ( <div className="App"> {/* ?? Type ‘{}‘ is missing the following properties from type ‘HTMLInputElement‘:... */} <input type="text" ref={this.inputRef} /> </div> ); } } 像上面那样创建并使用存在两个问题。 一个是提示我们的引用无法赋值到 function createRef<T>(): RefObject<T>; 所以上面创建引用时,显式指定它的类型。 - private inputRef = React.createRef(); + private inputRef = React.createRef<HTMLInputElement>(); 第二个问题是即使在 componentDidMount() { + if(this.inputRef.current){ this.inputRef.current.focus(); + } } 还可通过变量后添加 componentDidMount() { - this.inputRef.current.focus(); + this.inputRef.current!.focus(); } 修复后完整的代码如下: class App extends Component<{}, {}> { private inputRef = React.createRef<HTMLInputElement>(); componentDidMount() { this.inputRef.current!.focus(); } render() { return ( <div className="App"> <input type="text" ref={this.inputRef} /> </div> ); } } React + TypeScript 组件引用的传递继续到组件的情况,当需要引用的元素在另一个组件内部时,还是通过 这是该方法的签名: function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>; 可以看到,方法接收两个类型参数, 所以添加引用传递后, const FancyInput = React.forwardRef<HTMLInputElement, {}>((props, ref) => { return <input type="text" ref={ref} className="fancy-input" />; }); 使用组件: class App extends Component<{}, {}> { private inputRef = React.createRef<HTMLInputElement>(); componentDidMount() { this.inputRef.current!.focus(); } render() { return ( <div className="App"> <FancyInput ref={this.inputRef} /> </div> ); } } 相关资源 |
原文地址:https://www.cnblogs.com/Wayou/p/react_typescript_forwardref.html