React之DOM操作

某些情況下需要在典型數(shù)據(jù)流外強制修改子代旦棉。要修改的子代可以是React組件實例锅论,也可以是DOM元素。這時就要用到 refs 來操作DOM

使用場景

下面是幾個適合使用 refs 的情況:

  1. 處理焦點铸史,文本選擇或媒體控制
  2. 觸發(fā)強制動畫
  3. 集成第三方DOM庫

如果可以通過聲明式實現(xiàn)庐橙,則盡量避免使用 refs惯吕。注意,不要在 Dialog 組件上直接暴露 open() 和 close() 方法怕午,最好傳遞 isOpen 屬性

ref

react 支持給任意組件添加特殊屬性。ref 屬性接受一個回調(diào)函數(shù)淹魄,它在組件被加載或卸載時會立即執(zhí)行郁惜。注意,在組件 mount 之后再去獲取ref甲锡。componentWillMount 和第一次 render 時都獲取不到兆蕉,在 componentDidMount 才能獲取到。

html元素

當(dāng)給HTML元素添加 ref 屬性時缤沦,ref 回調(diào)接收了底層的DOM元素作為參數(shù)虎韵。react 組件在加載時將DOM元素傳入ref的回調(diào)函數(shù),在卸載時則會傳入 null缸废。ref 回調(diào)會在 componentDidMount 或 componentDidUpdate 這些生命周期回調(diào)之前執(zhí)行包蓝。

class CustomTextInput extends React.Component {
    constructor(props) {
        super(props);
        this.focus = this.focus.bind(this);
    }
    focus() {
        this.textInput.focus();
    }
    render() {
        return(
            <div>
                <input type="text" ref={(input) => { this.textInput = input; }} />
                <input type="button" value="Focus the text input" onClick={ this.focus } />
            </div>
        )
    }
}

更簡短的寫法如下:

ref={ input => this.textInput = input }

類組件

當(dāng) ref 屬性用于使用class聲明的自定義組件時,ref的回調(diào)接收的是已經(jīng)加載的React實例企量。

class AutoFocusTextInput extends React.Component {
    componentDidMount() {
        this.textInput.focusTextInput();
    }
    render() {
        return (
            <CustomTextInput
            ref={(input) => { this.textInput = input; }} />
        );
     }
  }

注意测萎,這種方法僅對 class 聲明的 CustomTextInput 有效。

函數(shù)式組件

不能在函數(shù)式組件上使用 ref 屬性届巩,因為它們沒有實例硅瞧。

對父組件暴露DOM節(jié)點

在子節(jié)點上暴露一個特殊的屬性,子節(jié)點將會獲得一個函數(shù)屬性恕汇,并將其作為 ref 屬性附加到DOM節(jié)點腕唧。這允許父代通過中間件將 ref 回調(diào)給子代的DOM節(jié)點。

function Custom TextInput(props) {
  return(
    <div>
      <input ref={ props.inputRef }/>
    </div>
  )
}

class Parent extends React.Component {
  render() {
    return (
      <Custom TextInput 
        inputRef={ el => this.inputElement = el }
      />
    )
  }
}

在上面這個例子中瘾英,Parent 將它的 ref 回調(diào)作為一個特殊的 inputRef 傳遞給 CustomTextInput枣接,然后CustomTextInput 通過 ref 屬性將其傳遞給<input>。最終方咆,Parent 中的this.inputElement 將被設(shè)置為與CustomTextInput 中的<input>元素相對應(yīng)的DOM節(jié)點月腋。

非受控組件

要編寫一個受控組件,而非為每個狀態(tài)更新編寫事件處理程序,可以使用 ref 從DOM 獲取表單值榆骚。注意片拍,可能通過e.target.value 取得DOM值,而不用綁定react妓肢。

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleSubmit(event) {
    alert("A name was submitted:" + this.input.value);
    event.preventDefault();
  }
  render() {
    return(
      <form onSubmit={ this.handleSubmit }>
        <lable>
          Name: <input type="text"ref={ (input) => this.input = input } />
        </lable>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

由于非受控組件將真實數(shù)據(jù)保存在DOM中捌省,因此在使用非受控組件時,更容易同時集成React和非React代碼碉钠。

默認(rèn)值

在React的生命周期中纲缓,表單元素上的value屬性將會覆蓋DOM中的值。使用非受控組件時喊废,通常希望React可以為其指定初始值祝高,但不再控制后續(xù)更新。更解決這個問題污筷,可以指定一個 defaultValue屬性而不是value

render() {
  return(
    <form onSubmit={this.handleSubmit}>
      <lable>
        Name: <input dafaultValue="Bob" type="text" ref={ (input) => this.input = input } />
      </lable>
     <input type="submit" value="Submit" />
    </form>
  );
}

同樣工闺,<input type="checkbox">和<input type="radio">支持defaultChecked,<select>和<textarea>支持defaultValue瓣蛀。

ReactDOM

react-dom 這個軟件包提供了針對DOM的方法陆蟆,可以在應(yīng)用的頂級域中調(diào)用,也可以在有需要的情況下用作跳出React模型的出口惋增。但大部分組件都不應(yīng)該需要使用這個包叠殷。
render()
unmountComponentAtNode()
findDOMNode()

render()
ReactDOM.render(
  element,
  container,
  [callback]
)

渲染一個react元素,添加到位于提供的container里的DOM元素中诈皿,并返回這個組件的一個引用(或者對于無狀態(tài)組件返回null)林束。如果這個react元素之前已經(jīng)被渲染到container里去了,這段代碼就會進行一次更新纫塌,并且只會改變那些反映元素最新狀態(tài)所必須的DOM元素诊县。

unmountComponentAtNode()
ReactDOM.unmountComponentAtNode(container)

從DOM元素中移除已掛載的React組件,清除它的事件處理器和state措左。如果容器內(nèi)沒有掛載任何組件依痊,這個函數(shù)什么都不會干。有組件被卸載的時候返回true怎披,沒有組件可供卸載時返回false

findDOMNode()
ReactDOM.findDOMNode(component)

如果這個組件已經(jīng)被掛載到DOM中胸嘁,函數(shù)會返回對應(yīng)的瀏覽器中生成的DOM元素。需要從DOM中讀取值時凉逛,比如表單的值性宏,或者計算DOM元素的尺寸,這個函數(shù)會非常有用状飞。大多數(shù)情況下毫胜,可以添加一個指向DOM節(jié)點的引用书斜,從而完全避免使用findDOMNode這個函數(shù)。當(dāng)render返回null或者false時酵使,findDOMNode也返回null

新 ref

版本16.3之前荐吉,React 有兩種提供ref的方式:字符串和回調(diào),因為字符串的方式有些問題口渔,所以官方建議使用回調(diào)來使用ref样屠。而現(xiàn)在引入的createRef API,據(jù)官方說是一種零缺點的使用ref的方式缺脉,回調(diào)方式也可以讓讓路了痪欲。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

然后使用current屬性,即可獲得當(dāng)前元素 this.myRef.current攻礼,典型應(yīng)用如下所示:

constructor(props) {
  super(props);
  this.Mask = React.createRef()
  this.MenuList = React.createRef()
}
handleClick = () => {
  ReactDOM.findDOMNode(this.MenuList.current).classList.toggle("transform-zero")
  ReactDOM.findDOMNode(this.Mask.current).classList.toggle("mask-show")
}

注意业踢,使用 styleComponents 樣式化的元素暴露的接口是 innerRef,而不是ref

<Wrap innerRef={ this.itemRef }>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末礁扮,一起剝皮案震驚了整個濱河市陨亡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌深员,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛙埂,死亡現(xiàn)場離奇詭異倦畅,居然都是意外死亡,警方通過查閱死者的電腦和手機绣的,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門叠赐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人屡江,你說我怎么就攤上這事芭概。” “怎么了惩嘉?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵罢洲,是天一觀的道長。 經(jīng)常有香客問我文黎,道長惹苗,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任耸峭,我火速辦了婚禮桩蓉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘劳闹。我一直安慰自己院究,他們只是感情好洽瞬,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著业汰,像睡著了一般伙窃。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蔬胯,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天对供,我揣著相機與錄音,去河邊找鬼氛濒。 笑死产场,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的舞竿。 我是一名探鬼主播京景,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼骗奖!你這毒婦竟也來了确徙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤执桌,失蹤者是張志新(化名)和其女友劉穎鄙皇,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仰挣,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡伴逸,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了膘壶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片错蝴。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颓芭,靈堂內(nèi)的尸體忽然破棺而出顷锰,到底是詐尸還是另有隱情,我是刑警寧澤亡问,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布官紫,位于F島的核電站,受9級特大地震影響州藕,放射性物質(zhì)發(fā)生泄漏万矾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一慎框、第九天 我趴在偏房一處隱蔽的房頂上張望良狈。 院中可真熱鬧,春花似錦笨枯、人聲如沸薪丁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽严嗜。三九已至粱檀,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間漫玄,已是汗流浹背茄蚯。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留睦优,地道東北人渗常。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像汗盘,于是被迫代替她去往敵國和親皱碘。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

推薦閱讀更多精彩內(nèi)容