React 文檔 Part 2

—— 事件處理、

此文檔來自 React 官方文檔洞就,在英文原文的基礎(chǔ)上進(jìn)行了增刪改盆繁,用于我本人的研究與學(xué)習(xí),暫不支持轉(zhuǎn)載旬蟋。因?yàn)楸救说乃絾栴}油昂,來取經(jīng)的同學(xué)也請(qǐng)慎用。

事件處理

React 元素的事件處理與 DOM 元素的世界處理很相似倾贰,這里有幾點(diǎn)語法上的不同點(diǎn):

  • React 事件使用駝峰法命名而不是全部小寫冕碟。
  • 使用 JSX 時(shí)傳遞一個(gè)函數(shù)作為事件處理方法而不是一個(gè)字符串。

比如匆浙,使用 HTML:

<button onclick="activateLasers()">
  Activate Lasers
</button>

與 React 有些許不同:

<button onClick={activateLasers}>
  Activate Lasers
</button>

另一個(gè)不同點(diǎn)是安寺,你不可以使用返回 false 的方法來阻止默認(rèn)行為。需要調(diào)用 preventDefault() 方法首尼。比如挑庶,對(duì)于純 HTML 來說言秸,為了防止鏈接打開新頁面的默認(rèn)行為,你可以寫:

<a href="#" onclick="console.log('The link was clicked.'); return false">
  Click me
</a>

在 React 中迎捺,替代方法如下:

function ActionLink() {
  function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
  }

  return (
    <a href="#" onClick={handleClick}>
      Click me
    </a>
  );
}

在此举畸,e 是一個(gè)合成事件。React 根據(jù) W3C spec 定義了這些合成事件凳枝,所以你不需要考慮跨瀏覽器兼容問題抄沮。

當(dāng)你使用 React 你基本不需要調(diào)用 addEventListener 來給 DOM 元素添加監(jiān)聽事件。取而代之的范舀,只需要在元素最開始被創(chuàng)建時(shí)提供一個(gè)監(jiān)聽即可合是。

當(dāng)你使用 ES6 定義一個(gè)組件了罪,通常的做法是將事件監(jiān)聽作為 class 的一個(gè)方法锭环。比如,下面這個(gè) Toggle 組件渲染了一個(gè)按鈕泊藕,可以讓用戶在 ON 和 OFF 之間轉(zhuǎn)換辅辩。

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // This binding is necessary to make 'this' work in the callback
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    this.setState(prevState => ({
      isToggleOn: !prevState.isToggleOn
    }));
  }
  render() {
    return (
        <button onClick={this.handleClick}>
          {this.state.isToggleOn ? 'ON' : 'OFF'}
        </button>);
    }
}

ReactDOM.render (
  <Toggle />,
  document.getElementById('root')
);

你必須要注意 JSX 回調(diào)函數(shù)中 this 的含義。在 JavaScript 中娃圆,類方法通常都不會(huì)自動(dòng)綁定玫锋。如果你忘了綁定 this.handleClick 而且將其傳遞給 onClick,當(dāng)函數(shù)被調(diào)用時(shí)讼呢,this 就會(huì)是 undefined撩鹿。

這不是 React 的特殊行為;這是 JavaScript 函數(shù)工作原理的一部分悦屏。通常情況下节沦,如果你更喜歡調(diào)用不帶()的方法,例如 onClick = {this.handleClick}础爬,你應(yīng)該綁定方法甫贯。

如果決定 bind 很煩的話,下面有兩個(gè)變通方法看蚜。如果你使用尚在實(shí)驗(yàn)的 public class fields syntax叫搁,你可以使用 類字段(class fields)來正確地綁定回調(diào)函數(shù):

class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.
  // Warning: this is *experimental* syntax.
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

這種格式在 Create React App中是默認(rèn)可用的。

如果你不想使用類字段格式供炎,你可以在回調(diào)函數(shù)中使用箭頭格式:

class LoggingButton extends React.Component {
  handleClick() {
    console.log ('this is"', this);
  }
  render () {
    // 這種格式可以確保 this 與 handleClick 綁定
    return (
      <button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>
    );
  }
}

這種格式帶來的問題是當(dāng)每次 LoggingButton 渲染時(shí)都會(huì)創(chuàng)建不同的回調(diào)函數(shù)渴逻。在大多數(shù)的場(chǎng)景里,這是沒問題的音诫。然而惨奕,如果這個(gè)回調(diào)函數(shù)是作為一個(gè) 屬性 被傳遞到下層的組件中,這些組件可能會(huì)額外做一次渲染纽竣。我們通常推薦前兩種方法墓贿,來避免問題蒂教。

向事件處理器傳遞參數(shù)

在循環(huán)中,通常都需要向每個(gè)事件處理方法中傳入一個(gè)額外的計(jì)數(shù)參數(shù)赤兴。如下所示腔稀,假設(shè) id 是行ID,下面兩種方法都可以正常運(yùn)行:

<button onClick={(e) => this.deleteRow(id. e)}> Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

上面這兩種是等價(jià)的幽勒,各自使用了箭頭函數(shù)和 Function.prototype.bind嗜侮。

在這兩種方法中,參數(shù) e 會(huì)作為在 ID 之后的第二個(gè)參數(shù)傳入 React 事件中啥容。在箭頭函數(shù)中锈颗,我們必須明確地傳給它,但是使用 bind 時(shí)咪惠,多余的參數(shù)會(huì)自動(dòng)傳入击吱。

條件渲染

在 React 中,你可以創(chuàng)建不同的組件來封裝你想要完成的行為遥昧。然后你可以渲染其中的部分覆醇,決定于你組件的 state。

React 中的條件渲染的工作原理和 JavaScript 中的條件判斷相同炭臭。使用 JavaScript 操作符類似 if 和 條件操作符來創(chuàng)建由當(dāng)前狀態(tài)決定的元素永脓,然后讓 React 更新 UI 來匹配它們。

查看下面兩個(gè)組件:

function UserGreeting (props) {
  return <h1>Welcome back!</h1>;
}
function GusetGreeting (props) {
  return <h1>Please sign up.</h1>
}

我們創(chuàng)建了一個(gè) Greeting 組件鞋仍,其最終展示的內(nèi)容決定于哪個(gè)用戶進(jìn)行了登錄:

function Greeting (props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <userGreeting />;
  }
  return <GuestGreeting />;
}

ReactDOM.render(
  // Try changing to isLoggedIn = {true}
  <Greeting isLoggedIn = {false} />,
  document.getElementById('root')
);

在這個(gè)例子中常摧,渲染哪個(gè)問候語句取決于屬性 isLoggedIn 的值。

元素變量

你可以使用變量來存儲(chǔ)元素威创。這可以幫助你在其他部分的輸出不變的情況下條件渲染一部分組件落午。

來看下面兩個(gè)新組件,分別為登錄和登出按鈕那婉。

function LoginButton(props) {
  return (
    <button ocClick={props.onClick}
      Login
    </button>
  );
}
function LogoutButton(props) {
  return (
    <button onClick={props.onClick}>
      Logout
    </button>
  );
}

在下面這個(gè)例子中板甘,我們創(chuàng)建一個(gè)包含狀態(tài)的組件 LoginControl。

這個(gè)組件會(huì)根據(jù)當(dāng)前的狀態(tài)來渲染 <LoginButton /> 或者 <LogoutButton />详炬。同時(shí)也會(huì)渲染前面例子中的 <Greeting /> 組件盐类。

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bing(this);
    this.state = {isLoggedIn: false};
  }
  handleLoginClick() {
    this.setState({isLoggedIn: true});
  }
  handleLogoutClick() {
    this.setState({isLoggedIn: false});
  }
  render () {
    const isLoggedIn = this.state.isLoggedIn;
    let button = null;
    if (isLoggedIn) {
      button = <LogoutButton onClick = {this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick = {this.handleLoginClick} />;
    }

  return (
    <div>
      <Greeting isLoggedIn = {isLoggedIn}
        {button}
      </div>
    );
  }
}

ReactDOM.render(
  <LoginControl />,
  document.getElementById('root')
);

定義一個(gè)變量,使用 if 條件判斷是條件渲染組件的一種很好的方法呛谜,有時(shí)你可能想要使用更簡(jiǎn)潔的格式在跳。下面有幾種在 JSX 中使用條件判斷的例子。

內(nèi)聯(lián) if 和 邏輯 && 運(yùn)算符

你可以在 JSX 中嵌入任何表達(dá)式隐岛,當(dāng)然也包括 JavaScript 的 邏輯運(yùn)算符 &&猫妙。可以方便地在一個(gè)元素中使用條件渲染:

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 &&
        <h2>
          You have {unreadMessages.length} unread messages.
        </h2>
      }
    </div>
  );
}

const messages = ['React', 'Re: React', 'Re:Re: React'];
ReactDOM.render(
  <Mailbox unreadMessages={messages} />,
  document.getElementById('root')
);

在 JavaScript 中可以這樣用聚凹,因?yàn)?true && expression 的值總是決定于 expression割坠,false && expression 的值總是 false齐帚。

因此,如果條件判斷為 true彼哼,元素右邊 && 之后的會(huì)在輸出中顯示对妄。如果條件判斷為 false,React 會(huì)忽略后面的值敢朱。

內(nèi)聯(lián) If-Else 與條件運(yùn)算符

另一個(gè)內(nèi)聯(lián)的方法是使用 condition ? true : false 條件運(yùn)算符剪菱。
在下面這個(gè)例子中,我們使用這種方法渲染一小段文字:

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    </div>
  );
}

它同樣可以在大一點(diǎn)的表達(dá)式中使用拴签,雖然它的可讀性差一些孝常。

render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.handleLogoutClick} />
      ) : (
        <LoginButton onClick={this.handleLoginClick} />
      )}
    </div>
  );
}

就像在 JavaScript 中一樣,你和你的團(tuán)隊(duì)可以根據(jù)可讀性的需求來選擇不同的方法蚓哩。同樣記住一點(diǎn)就是构灸,如果條件變得很復(fù)雜,就該分離組件了杖剪。

讓組件不被渲染

在有些情況下冻押,你可能想要組件被渲染后隱藏驰贷。想要實(shí)現(xiàn)只需要返回 null 而不是它的輸出盛嘿。
在下面這個(gè)例子中,<WarningBanner /> 是否渲染是由其屬性 warn 的值決定的括袒,如果這個(gè)屬性的值是 false的次兆,組件就不會(huì)渲染:

function WarningBanner (props) {
  if(!props.warn) {
    return null;
  }
  return (
    <div className = "warning">
      Warning!
    </div>
  );
}

class Page extends React.Component {
  constructor() {
    super(props);
    this.state = {showWarning: true};
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }
  handleToggleClick () {
    this.setState(prevState => ({showWarning: !prevState.showWarning}));
  }
  render() {
    return (
      <div>
        <WarningBanner warn = {this.state.showWarning} />
        <button onClick = {this.handleToggleClick}>
          {this.state.showWarning ? 'Hide' : 'Show'}
        </button>
      </div>
    );
  }
}

ReactDOM.render (
  <Page />,
  document.getElementById('root')
);

在組件的 render 方法中返回 null 并不會(huì)影響組件的生命周期方法。例如锹锰,componentDidUpdate 和 componentWillUpdate 仍然會(huì)調(diào)用芥炭。

列表和值

首先我們來回顧一下在 JavaScript 中你是如何處理列表的。
查看下面的代碼恃慧,我們使用 map() 函數(shù)將 numbers 的
每個(gè)數(shù)字double园蝠。我們將 map() 的返回值賦值給 doubled 然后輸出:

const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((number) => number * 2);
console.log (doubled);

這段代碼會(huì)在控制臺(tái)輸出 [1, 4, 6, 8, 10];

在 React 中,將數(shù)組轉(zhuǎn)換為元素列表也是與之類似的痢士。

渲染多個(gè)組件

你可以創(chuàng)建多個(gè)元素并且用 {} 將他們放在 JSX 中彪薛。

在下面,我們使用 JavaScript 的 map() 函數(shù)來循環(huán) numbers 數(shù)組怠蹂,每項(xiàng)返回一個(gè) <li> 元素善延,并且將其放入 listItems中:

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => 
  <li>{number}</li>
);

我們把整個(gè) listItems 數(shù)組放在一個(gè) <ul> 元素中,并且將其渲染到 DOM 中:

ReactDOM.render(
  <ul>{listItems}</ul>,
  document.getElementById('root')
);

這段代碼會(huì)展示從1到5的列表城侧。

基本的列表組件

通常情況下易遣,你要在組件里渲染列表。

我們可以在組件中重構(gòu)上面的代碼嫌佑,組件接受一個(gè)數(shù)字?jǐn)?shù)組豆茫,然后輸出一個(gè)無序列表元素侨歉。

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) => 
    <li>{number}</li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render (
  <NumberList numbers = {number} />,
  documents.getElementById('root')
);

當(dāng)你運(yùn)行這段代碼,你會(huì)得到一個(gè)警告:你應(yīng)該給列表中的每一項(xiàng)賦予一個(gè) 鍵(key)揩魂。鍵 是一個(gè)特殊的字符串屬性为肮,當(dāng)你創(chuàng)建一個(gè)元素列表時(shí),每一個(gè)元素都應(yīng)該擁有肤京。在下一節(jié)中我們會(huì)討論鍵為什么這么重要颊艳。

我們給 numbers.map() 中的每一個(gè)元素分配一個(gè) key 來解決 key 的問題:

function NumberList (props) {
  const numbers = props.numbers;
  const listItems = number.map((number) => 
    <li key = {number.toString()}>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}
const numbers = [1, 2, 3, 4, 5];
ReactDOM.render (
  <NumberList numbers = {numbers} />,
  document.getElementById('root')
);

鍵 Key

Key 可以幫著 React 識(shí)別哪些項(xiàng)發(fā)證了改變,被添加忘分,或被移除棋枕。每個(gè)數(shù)組中的元素都應(yīng)該賦予一個(gè) key 來給予他們一個(gè)穩(wěn)定的標(biāo)志:

const numbers = [1, 2, 3, 4, 5];
const listItens = numbers.map((number) => 
  <li key = {number.toString()}>
    {number}
  </li>
);

選取 key 值的最好方法是使用一個(gè)不同于其兄弟節(jié)點(diǎn)的字符串來進(jìn)行標(biāo)識(shí)。通常會(huì)使用數(shù)據(jù)的 ID 值妒峦。

const todoItems = todos.map((todo) =>
  <li key = {todo.id}>
    {todo.text}
  </li>
);

如果你要渲染的項(xiàng)沒有一個(gè)穩(wěn)定的 ID 值重斑,那么你可以使用項(xiàng)的索引來當(dāng)做 key:

const todoItems = todos.map((todo, index) => 
  // 只用在項(xiàng)沒有穩(wěn)定的 ID 情況下
  <li key = {index}>
    {todo.text}
  </li>
);

我們不推薦在項(xiàng)可能被重新排序的情況下使用索引來作為 key 值,因?yàn)槟菢訒?huì)降低效率肯骇。如果感興趣的話你也可以查看 key 值重要的深層次原因窥浪。

** To Be Continued...**

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市笛丙,隨后出現(xiàn)的幾起案子漾脂,更是在濱河造成了極大的恐慌,老刑警劉巖胚鸯,帶你破解...
    沈念sama閱讀 219,427評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件骨稿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡姜钳,警方通過查閱死者的電腦和手機(jī)坦冠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來哥桥,“玉大人辙浑,你說我怎么就攤上這事∧飧猓” “怎么了判呕?”我有些...
    開封第一講書人閱讀 165,747評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)已卸。 經(jīng)常有香客問我佛玄,道長(zhǎng),這世上最難降的妖魔是什么累澡? 我笑而不...
    開封第一講書人閱讀 58,939評(píng)論 1 295
  • 正文 為了忘掉前任梦抢,我火速辦了婚禮,結(jié)果婚禮上愧哟,老公的妹妹穿的比我還像新娘奥吩。我一直安慰自己哼蛆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,955評(píng)論 6 392
  • 文/花漫 我一把揭開白布霞赫。 她就那樣靜靜地躺著腮介,像睡著了一般。 火紅的嫁衣襯著肌膚如雪端衰。 梳的紋絲不亂的頭發(fā)上叠洗,一...
    開封第一講書人閱讀 51,737評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音旅东,去河邊找鬼灭抑。 笑死,一個(gè)胖子當(dāng)著我的面吹牛抵代,可吹牛的內(nèi)容都是我干的腾节。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼荤牍,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼案腺!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起康吵,我...
    開封第一講書人閱讀 39,352評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤劈榨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后涎才,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鞋既,經(jīng)...
    沈念sama閱讀 45,834評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,992評(píng)論 3 338
  • 正文 我和宋清朗相戀三年耍铜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跌前。...
    茶點(diǎn)故事閱讀 40,133評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡棕兼,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抵乓,到底是詐尸還是另有隱情伴挚,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評(píng)論 5 346
  • 正文 年R本政府宣布灾炭,位于F島的核電站茎芋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏蜈出。R本人自食惡果不足惜田弥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,477評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望铡原。 院中可真熱鬧偷厦,春花似錦商叹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至请唱,卻和暖如春弥咪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背十绑。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工酪夷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人孽惰。 一個(gè)月前我還...
    沈念sama閱讀 48,398評(píng)論 3 373
  • 正文 我出身青樓晚岭,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親勋功。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坦报,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,077評(píng)論 2 355

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

  • 本筆記基于React官方文檔,當(dāng)前React版本號(hào)為15.4.0狂鞋。 1. 安裝 1.1 嘗試 開始之前可以先去co...
    Awey閱讀 7,712評(píng)論 14 128
  • 原教程內(nèi)容詳見精益 React 學(xué)習(xí)指南片择,這只是我在學(xué)習(xí)過程中的一些閱讀筆記,個(gè)人覺得該教程講解深入淺出骚揍,比目前大...
    leonaxiong閱讀 2,840評(píng)論 1 18
  • 深入JSX date:20170412筆記原文其實(shí)JSX是React.createElement(componen...
    gaoer1938閱讀 8,070評(píng)論 2 35
  • 以下內(nèi)容是我在學(xué)習(xí)和研究React時(shí)字管,對(duì)React的特性、重點(diǎn)和注意事項(xiàng)的提取信不、精練和總結(jié)嘲叔,可以做為React特性...
    科研者閱讀 8,236評(píng)論 2 21
  • 最近看了一本關(guān)于學(xué)習(xí)方法論的書,強(qiáng)調(diào)了記筆記和堅(jiān)持的重要性抽活。這幾天也剛好在學(xué)習(xí)React硫戈,所以我打算每天堅(jiān)持一篇R...
    gaoer1938閱讀 1,685評(píng)論 0 5