React文檔翻譯 (快速入門)

翻譯自react的大部分文檔,方便本身查閱。javascript

目錄

生命週期

僅僅關於客戶端的Reacthtml

實例化

  1. getDefaultProps()
  2. getInitialState()
  3. componentWillMount()
  4. render()
  5. componentDidwMount()

存在期

  1. componentWillReceiveProps()
  2. shouldComponentUpdate()
  3. componentWillUpdate()
  4. componentDidUpdate()

銷燬期

  1. componentWillUnmount

state

Do Not Modify State Directly

不能直接設置state, 這不會再次渲染一個component(this will not re-render a component), 只有一個地方能夠直接設置state。java

// wrong, this this.state = { comments: 'Hello world'};

應該使用setState()方法。react

// true this.setState({ comments: 'Hello world', });

State Updates May Be Asynchronous

React能夠將多個setState()調用分批到單個更新中以實現性能。git

由於this.propsthis.state均可能是異步更新,所以不能夠依靠它們的值來計算下一次的state。舉例來講,下面就是錯的:es6

// wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

 

爲了解決這個問題,使用setState()的第二種形式,它接受一個函數,函數的第一個參數是以前的state, 第二個參數是props。github

// correct
this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment,
}));

State Updates are Merged

當你調用setState()的時候,React合併你提供的對象到當前的state當中。(When you call setState(), React merges the object you provide into the current state.)segmentfault

The Data Flows Down

條件渲染(Conditional Rendering)

使用&&操做符替換if

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

 

可是這種方法,值得注意的是,return後面跟的最外層必須是html元素。而不能是下面這樣:數組

function MailBox(props) {
  return (
    {unreadMessages.length > 0 &&
      <h2>
        You have {unreadMessages.length} unread messages.
      </h2>
    }
  );
}

 

使用?:替換if else

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

還能夠用於更大的表達式。瀏覽器

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

Preventing Component from Rendering

極少的狀況下,要讓組件隱藏起來,那麼能夠經過return null來實現。

Lists and Keys

在react中使用list,必需要爲每一個list的元素指定key(每一個item的key是惟一的)。

Keys

keys幫助React肯定哪些item已經改變了,被添加了或者被移除了。

不推薦設置key的值是索引,若是這個數組要被排序的話(We don't recommand using indexes for keys if the items can reorder, as that would be slow.)。由於這將會被慢。

key只在周圍數組的上下文中有意義。

表單

在react中,HTML表單元素與其餘DOM元素有所不同。由於表單元素天然保持着一些內部狀態。舉例來講,這個HTML格式的表單接受一個單個的name:

<form>
  <label>
    Name:
    <input type="text" name="name" />
  </label>
  <input type="submit" value="Submit" />
</form>

這個表單擁有HTML表單的默認行爲,當提交表單的時候,瀏覽器會打開一個新的頁面。若是你在react中這麼使用的話,它依然起做用。可是在大多數狀況下,擁有一個能夠處理表單並可訪問用戶輸入表單的數據的JavaScript函數是很方便的。實現這一點的標準方法是使用一種叫做'受控組件'的技術。

受控組件

在HTML中,相似於input textarea select這樣的表單元素一般維持着它們本身的狀態,而且基於用戶的輸入更新。在React中,可變狀態一般保存在組件的state屬性中,而且只能經過setState()來更新。

咱們能夠經過使react成爲'真正的惟一來源', 將二者結合起來。而後,呈現表單的React組件也控制後續用戶輸入時該表單中發生的狀況。 一個輸入表單元素的值被React控制,被稱爲受控組件。

一個簡單的受控組件以下:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: '',};
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(e) {
    this.setState({
      value: e.target.value,
    });
  }

  handleSubmit(e) {
    console.log(this.state.value);
    e.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          name:
          <input type="text" value={this.state.value} onChange={this.handleChange} />
        </labeL>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

 

使用受控組件,每一個狀態的突變都具備相關聯的處理函數。這使得修改或驗證用戶的輸入很直接。舉例來講,若是咱們想要用戶強制性這些名稱用所有大寫字母寫,咱們能夠把handleChange寫爲:

handleChange(e) {
  this.setState({
    value: e.target.value.toUpperCase(),
  });
}

The textarea tag

在HTML中,一個textarea元素定義它的文本經過children來定義。

而在React中,一個textarea元素是使用value屬性來定義的。其使用方法和input差很少的。

Select

在HTML中,select建立一個下拉列表,好比像下面這樣的:

<select>
  <option value="baoma">baoma</option>
  <option selected value="benchi">benchi</option>
  <option value="aodi">aodi</option>
</select>

而在React中,是在根select組件裏使用value屬性來選中的。在受控組件中,這更加方便,由於你只須要在一個地方更新它,好比下面這樣:

class FormItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'benchi'};
    this.handleChange = this.handleChange.bind(this); 
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(e) {
    this.setState({
      value: e.target.value,
    });
  }

  handleSubmit(e) {
    console.log(e.state.value);
    e.preventDefault();
  }

  render(
    return (
      <form onSubmit={this.handleSubmit}
        <label>
          Pick your favorite car:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="baoma">baoma</option>
            <option value="benchi">benchi</option>
            <option value="aodi">aodi</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      />
    );
  );
}
<input type="text" /> <textarea> <select>它們都工做的差很少,它們都接受一個屬性,這個屬性能夠用來實現一個受控組件。value

Handling Multiple Inputs

當你須要處理多個受控組件input元素的時候,你能夠給每一個元素添加name屬性,而且讓處理函數根據該值(event.target.name)選擇要進行的操做。

舉個例子:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.setState = {
      isGoing: true,
      numberOfGuests: 2,
    };

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    const target = e.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    // es6 computed property name
    this.setState({
      [name]: value,
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <Input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleChange} />
        </label>
        </br>
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value=={this.state.numberOfGuests}
            onChange={this.handleChange} />
        </label>
      </form>
    );
  }
}

可能你以爲太麻煩,你須要非受控組件

Lifting State Up

在react中,共享state是經過將它移動到須要它的組件的最接近的共同祖先來實現的。這被稱爲提高狀態。若是祖先擁有了共享狀態,那麼就有了source of true

官方文檔給的那個例子,簡單來講,兩個組件的值相互依賴的時候,就將state提高到它們最近的共同祖先,經過在父組件裏進行相應的值轉換,而後經過props將值傳遞給子組件。而後兩個子組件的值改變時,調用的函數是父組件傳遞下來的。

所以, 能夠經過子組件調父組件傳遞過來的函數,將子組件的值傳遞給父組件, 來改變父組件的state, 而後父組件計算值後,經過props將計算後的值分發到各個子組件,這樣就保證了惟一的來源,而子組件的值也是相互依賴(有關聯)的。 以下:

// 子組件
handleChange(e) {
  this.props.onTemperatureChange(e.target.value);
}
<input onChange={this.handleChange} type="text" />

// 父組件
handleChange(value) {
  this.setState({
    temperature: value,
  }); 
}
<TemperatureInput
  onTemperatureChage={this.handleChange} />

組合與繼承

在React中,咱們推薦使用組合來複用代碼而不是繼承。

Containment

一些容器不能提早知道它們的children是誰。在SidebarDialog裏尤爲的正常。

咱們推薦這類的組件使用特殊的children prop來將children直接傳遞到它們的輸出中:

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {this.props.children}
   </div>
  );
}

而後讓其餘組件經過嵌入JSX傳遞任意個child給FancyBorder:

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        Welcome
      </h1>
      <p className="Dialog-message">
        Thank you for visiting our spacecraft!
      </p>
    </FancyBorder>
  );
}

<FancyBorder>JSX標籤中的任何內容都會做爲子菜單傳入FancyBorder組件。因爲FancyBorder{props.children}呈如今

中,因此傳遞的元素將顯示在最終輸出中。通常在開發中,還能夠在路由中控制 this.props.children是誰。好比下面這樣:
// News.js
render() {
  return (
    <div className={style.container}>
      {this.props.children}
    </div>
  );
}

// routers.js
export function createRoutes() {
  return {
    path: '/',
    component: App,
    indexRoute: { component: Main },
    childRoutes: [
      {
        path: ':channel',
        component: NewsList,
      }
    ],
  };
}

這裏News組件的子組件就是NewsList。

雖然不常見,可是有時候你可能在組件裏須要多個'hole', 在這種狀況下,你可能想出本身的習慣,而不是使用children:

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">
        {props.left}
      </div>
      <div className="SplitPane-right">
        {props.right}
      </div>
    </div>
  );
}

function App() {
  return (
    <SplitPane
      left={
        <Contacts />
      }
      right={
        <Chat />
      }
    />
  );
}

特殊化(Specialization)

有時咱們將組件視爲其餘組件的"特殊狀況"。舉例來講,咱們能夠說WelcomeDialogDialog的一種特殊狀況。

在React中,這一般由組合來實現,其中一個更"特定"的組件呈現出更"通用的組件", 而且使用props來配置它。

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-title">
        {props.message}
      </p>
    </FancyBorder>
  );
}

function WelcomeDialog() {
  return (
    <Dialog
      title="Welcome"
      message="Thank you for visiting our spacecraft!" />
  );
}

組合對於定義爲類的組件一樣適用。

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">
        {props.title}
      </h1>
      <p className="Dialog-message">
        {props.messgae}
      </p>
      {props.children}
    </FancyBorder>
  ); 
}

class SignUpDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSignUp = this.handleSignUp.bind(this);
    this.state = {login: ''};
  }

  handleChange(e) {
    this.setState({
      login: e.target.value,
    });
  }

  handleSignUp() {
    alert(`Welcome aboard, ${this.state.login}!`);
  }

  render() {
    return (
      <Dialog
        title="Mars Exploration Program"
        message="How should we refer to you?">
        <input
          value={this.state.login}
          onChange={this.handleChange} />
        <button onClick={this.handleSignUp}>
          Sign Me Up!
        </button>
      </Dialog>
    );
  }
}

So What About Inheritance?

在Facebook, 咱們在數千計的組件中,尚未發現任何一種狀況值得咱們推薦使用繼承。使用Props和composition就已經很完美了。

思考React

Step1: Break The UI Into A Component Hierarchy

使用單一任務原則,也就是說,一個組件理想上只作一件事情。

Step2: Build A Static Version In React

使用mock數據構架一個沒有交互的靜態版本。由於構建一個靜態的版本,須要大量的typing和不須要思考太多,而構建一個交互性的版本須要大量的思考,而不須要大量的typing
若是你很熟悉state的概念,那麼就不要使用state來構建靜態的版本, state只是爲了交互而保留的。
你既能夠自下向上進行構建,也能夠自上向下構建。在簡單的例子中,一般更容易自上而下;而在較大的例子中,自下而上一般更容易一些,而且也更容易寫測試。

Step3: Identify The Minimal (but complete) Representation Of UI State

要使你的應用能夠交互,你須要可以觸發底層數據模型的更改, State讓這一切變得很容易。
爲了正確的構建你的app,首先你須要思考你的app須要的最小的可變的state集。這裏很關鍵的是DRY: Don't repeat yourself。找出你的app須要的state集的最小表示,並計算出你所須要的其餘需求。舉例來講,若是你要構建一個Todo List, 只須要維持一個todo items的數組,不須要爲數量單獨保持一個state的變量。當你想要渲染todo的數量時,只須要取todos數組的長度就能夠了。

如何區分是數據是state仍是props,只須要問下面這三個問題:

  1. 它是從父組件從props傳遞過來的嗎?若是是,那麼它不是state。
  2. 它會隨着時間的推移保持不變嗎?若是是,那麼它不是state。
  3. 你能夠根據組件中的其餘state或props計算出它來嗎?若是能夠,那麼它不是state。

Step4: Identify Where You State Live

當咱們肯定app的最小的state集後。下一步,咱們須要肯定是哪個組件擁有state。
記住: React是單向數據流,可能不能當即清楚哪一個組件擁有哪一個state。這對於新手來講也是最大的挑戰,所以根據下面這些步驟來解決這個問題:

對於你的應用中的每一個state:

  • 識別出基於那個state渲染的全部組件。
  • 找一個通用的組件find a common owner component(單個組件,它是全部須要那個state的組件的父級組件)。
  • 公共全部者(The common owner)或層次結構中較高的其餘組件應該擁有state。
  • 若是你找不到擁有state的組件,就建立一個新的組件,僅用於保存state,並將其添加到全部者組件上方的層次結構中。

Step5: Add Inverse Data Flow

子組件經過props調用父級組件 傳遞過來的方法(回調)來改變父級的state。

參考

react官方文檔
react生命週期

相關文章
相關標籤/搜索