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生命周期