您好,登錄后才能下訂單哦!
本篇內容主要講解“React ref的使用案例”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“React ref的使用案例”吧!
官網介紹:
在典型的 React 數據流中,props 是父組件與子組件交互的唯一方式。要修改一個子組件,你需要使用新的 props 來重新渲染它。但是,在某些情況下,你需要在典型數據流之外強制修改子組件。被修改的子組件可能是一個 React 組件的實例,也可能是一個 DOM 元素。對于這兩種情況,React 都提供了解決辦法,即使用 ref 來獲取 dom 或組件實例。
這是 ref 最直接的用法
export class Demo extends React.Component { constructor(props) { super(props) this.myRef = createRef() } componentDidMount() { console.log(this.myRef) } render() { return <div ref={this.myRef}>測試</div> } }
打印看一下 ref 是啥
可以看出,ref.current 拿到了 dom 元素,所以我們可以實現 dom 元素本身的一些功能,如 input 的聚焦:
export class Demo extends React.Component { constructor(props) { super(props) this.myRef = createRef() } onClick = () => { this.myRef.current.focus() } render() { return ( <div> <button onClick={this.onClick}>聚焦</button> <input ref={this.myRef} /> </div> ) } }
官網還提供了一種 ref 回調的形式:
export class Demo extends React.Component { constructor(props) { super(props) this.myRef = null } onClick = () => { this.myRef.focus() } render() { return ( <div> <button onClick={this.onClick}>聚焦</button> <input ref={ele => this.myRef = ele} /> // 這里的 ele 就是該 dom 元素 </div> ) } }
其實組件跟原生 dom 差不多,也是擁有自己的 ui、一些功能的某種元素,所以將 ref 放在組件上,也可以獲取到該組件的示例。
// 子組件 class Child extends React.Component { constructor(props) { super(props) this.state = { name: 'xx' } } render() { return <div>子元素{this.state.name}</div> } } export class Demo extends React.Component { constructor(props) { super(props) this.myRef = createRef() } componentDidMount() { console.log(this.myRef) } render() { return ( <Child ref={this.myRef} /> ) } }
那既然可以獲取到子組件的實例,我們就可以操作子組件了,比如文章最開始說,我想在父組件里去撈子組件的某些狀態值。
class Child extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } onClick = () => { this.setState({count: this.state.count+1}) } render() { return <button onClick={this.onClick}>點擊+1:{this.state.count}</button> } } export class Demo extends React.Component { constructor(props) { super(props) this.myRef = createRef() } onClick = () => { console.log(this.myRef.current.state.count) // 拿到子組件的狀態值 } render() { return ( <div> <button onClick={this.onClick}>獲取子組件的點擊次數</button> <Child ref={this.myRef} /> // ref 獲取到子組件實例 </div> ) } }
既然能拿值,我也能拿函數去修改子組件
class Child extends React.Component { constructor(props) { super(props) this.state = { name: 'xx' } } changeName = () => { this.setState({name: 'ww'}) } render() { return <div>子元素{this.state.name}</div> } } export class Demo extends React.Component { constructor(props) { super(props) this.myRef = createRef() } onClick = () => { this.myRef.current.changeName() // 父組件的手伸到子組件里去啦 } render() { return ( <div> <button onClick={this.onClick}>改變子組件的狀態</button> <Child ref={this.myRef} /> </div> ) } }
當然這個例子并不恰當,父組件想更改子組件的狀態的話,應該把狀態提升到父組件中,然后作為子組件的props傳遞進去。
主要是 ref 提供一種方式去繞過 props 來實現父子組件通信。
這是我文章開頭寫需求時犯的錯,ref 不能放在函數組件上,因為函數組件沒有實例。
const Child = () => { return <div>子組件</div> } export const Demo = () => { const myRef = useRef() // 可以在函數組件內創建 ref useEffect(() => { console.log(myRef) }, []) return <Child ref={myRef} /> // 但是放在函數組件上無效 }
那函數組件就不能使用 ref 了嗎,那肯定不是哈哈。我們可以使用 forwardRef 包裝函數組件。
const Child = (props, ref) => { // 包裝后,除了原有的 props 外, ref 也被傳了進來 return <div ref={ref}>子組件</div> // 還是得掛載到 dom 上 } const ProChild = React.forwardRef(Child) // 重點在這里 export const Demo = () => { const myRef = useRef() useEffect(() => { console.log(myRef) }, []) return <ProChild ref={myRef} /> }
這里貼一下官網的 tip:
那既然函數組件也可以使用 ref 的話,我們用函數組件實現一下父組件撈子組件的數據,不過可以看出,使用 forwardRef 包裹后,ref 還是得掛載到 dom 或者類組件上,如果我只想掛載數據還需要搭配 useImperativeHandle。
const Child = (props, ref) => { const [count, setCount] = useState(0) useImperativeHandle( ref, () => ({ // 這里就是暴露給外部 ref 的數據 getVal: ()=> count }), [count], ) const onClick = () => { setCount(pre => pre+1) } return <button onClick={onClick}>點擊+1:{count}</button> } const ProChild = React.forwardRef(Child) export const Demo = () => { const myRef = useRef() const onClick = () => { console.log(myRef.current.getVal()) // 拿到子組件的值 } return <><button onClick={onClick}>獲取子組件的點擊次數</button><ProChild ref={myRef} /></> }
至此完成了做需求時留下的問題 ?
最后還是需要強調一下,父組件獲取子組件狀態的場景,一般還是狀態提升 + 回調來通信,需求最終也是使用這種方式來實現的,最開始之所以想用 ref,是覺得狀態提升后,子組件變化了會引起父組件的重新渲染,但是我只想拿數據而不引起渲染。
跟師傅說了一下我寫需求時的想法,師傅見解如下:
優先考慮狀態提升
有性能問題的話,考慮狀態提升 + memo
不想給多個組件加 memo 的話,就要考慮引入 redux/mobx 了
如果引入 redux/mobx 是一種成本的話,那 ref 也不是不可以哈哈哈
到此,相信大家對“React ref的使用案例”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。