React + TypeScript:元素引用的传递
| 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.createRef() 方法完成的。使用的時候,通過其返回對象身上的 current 屬性可訪問到綁定引用的元素。 React 內部對引用的 current 賦值更新發生在 componentDidMount 或 componentDidUpdate 生命周期之前,即存在使用的時候引用未初始化完成的情況,所以 current 不一定有值。好的做法是使用前先判空。 if(this.inputRef.current){this.inputRef.current.focus() }在上面的示例中,之所以不用判空是因為我們在 componentDidMount 生命周期中使用,此時元素已經加載到頁面,所以可以放心使用。 組件中引用的傳遞對于原生 DOM 元素可以像上面那樣創建引用,但對于自己寫的組件,則需要使用 forwardRef() 來實現。 假如你寫了個按鈕組件,想要實現像上面那樣,讓使用者可通過傳遞一個 ref 屬性來獲取到組件中原生的這個 <button> 元素以進行相應的操作。 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" />; });forwardRef 接收一個函數,函數的入參中第一個是組件的 props,第二個便是外部傳遞進來的 ref 引用。通過將這個引用在組件中綁定到相應的原生 DOM 元素上,實現了外部直接引用到組件內部元素的目的,所以叫 forwardRef(傳遞引用)。 使用上面創建的 FancyInput,在組件加載后使其獲得焦點: 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>);} }像上面那樣創建并使用存在兩個問題。 一個是提示我們的引用無法賦值到 <input> 的 ref 屬性上,類型不兼容。引用需要與它真實所指代的元素類型相符,這正是 TypeScript 類型檢查為我們添加的約束。這個約束的好處是,我們在使用引用的時候,就知道這個引用真實的元素類型,TypeScript 會自動提示可用的方法和屬性,同時防止調用該元素身上沒有的屬性和方法。這里修正的方法很簡單,如果 hover 或 F12 查看 React.createRef() 的方法簽名,會發現它是個泛型方法,支持傳遞類型參數。 function createRef<T>(): RefObject<T>;所以上面創建引用時,顯式指定它的類型。 - private inputRef = React.createRef(); + private inputRef = React.createRef<HTMLInputElement>();第二個問題是即使在 componentDidMount 生命周期中使用,TypeScript 仍然提示 current 的值有可能為空。上面討論過,其實此時我們知道它不可能為空的。但因為 TypeScript 無法理解 componentDidMount,所以它不知道此時引用其實是可以安全使用的。解決辦法當然是加上判空的邏輯。 componentDidMount() { + if(this.inputRef.current){this.inputRef.current.focus(); + }}還可通過變量后添加 ! 操作符告訴 TypeScript 該變量此時非空。 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 組件引用的傳遞繼續到組件的情況,當需要引用的元素在另一個組件內部時,還是通過 React.forwardRef()。 這是該方法的簽名: function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;可以看到,方法接收兩個類型參數,T 為需要引用的元素類型,我們示例中是 HTMLInputElement,P 為組件的 props 類型。 所以添加引用傳遞后,FancyInput 組件在 TypeScript 中的版本應該長這樣: 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
總結
以上是生活随笔為你收集整理的React + TypeScript:元素引用的传递的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NSAssert的使用
- 下一篇: CPU芯片哪家强?电视处理器这么选就对了