翻译自react的大部分文档,方便自己查阅。

目录

生命周期

仅仅关于客户端的React

实例化

  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。

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

应该使用setState()方法。

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

State Updates May Be Asynchronous

React可以将多个setState()调用分批到单个更新中以实现性能。

因为this.propsthis.state都可能是异步更新,因此不可以依靠它们的值来计算下一次的state。举例来说,下面就是错的:

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

为了解决这个问题,使用setState()的第二种形式,它接受一个函数,函数的第一个参数是之前的state, 第二个参数是props。

// 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.)

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

React文档翻译 (快速入门)的更多相关文章

  1. React JS快速入门教程

    翻译至官方文档<Tutorial>http://facebook.github.io/react/docs/tutorial.html 转载请注明出处:http://blog.csdn.n ...

  2. React Native 快速入门之认识Props和State

    眼下React Native(以后简称RN)越来越火,我也要投入到学习当中.对于一个前端来说,还是有些难度.因为本人觉得这是一个App开发的领域,自然是不同.编写本文的时候,RN的版本为0.21.0. ...

  3. React 快速入门小记

    大约半个月前,我一直在思考一个问题,Angular.React 和 Vue,究竟该学什么? 听取了几位前辈的意见,也综合考虑了各方面的原因,最终选择了 React,希望我"没有选错" ...

  4. 快速入门react

    安装react npm install creat-react-app -g这里直接安装react的一个脚手架,里面包含了要用到的许多东西,帮助快速入门react 创建新项目 create-react ...

  5. React组件开发入门

    React 组件开发入门 Introduction 本文组成: Ryan Clark文章Getting started with React的翻译. 博主的实践心得. React由Facebook的程 ...

  6. .NET Core快速入门教程 2、我的第一个.NET Core App(Windows篇)

    一.前言 本篇开发环境?1.操作系统: Windows 10 X642.SDK: .NET Core 2.0 Preview 二.安装 .NET Core SDK 1.下载 .NET Core下载地址 ...

  7. .NET Core快速入门教程 3、我的第一个.NET Core App (CentOS篇)

    一.前言 本篇开发环境?1.操作系统:CentOS7(因为ken比较偏爱CentOS7)2.SDK版本:.NET Core 2.0 Preview 你可能需要的前置知识1.了解如何通过Hyper-V安 ...

  8. Vue (一) --- vue.js的快速入门使用

    =-----------------------------------把现在的工作做好,才能幻想将来的事情,专注于眼前的事情,对于尚未发生的事情而陷入无休止的忧虑之中,对事情毫无帮助,反而为自己凭添 ...

  9. webpack快速入门——给webpack增加babel支持

    1.Babel的安装与配置 Babel其实是几个模块化的包,其核心功能位于称为babel-core的npm包中,webpack可以把其不同的包整合在一起使用,对于每一个 你需要的功能或拓展,你都需要安 ...

随机推荐

  1. 预览github项目的html文件新方法

    原文地址:→看过来 写在前面 关于如何在线预览github中的html文件,其实这是一个很多人知道的东西,但是查资料的时候呢总是找不到正确的答案,并且一开始我也是踩了坑的. 踩坑经历 搜出来的结果大概 ...

  2. VR全景智慧城市-VR大时代

    这是一个创业的时代,这是一个创新的社会,我们的国家从没有像今天这样高度重视创业创新,我们的社会从没有像今天这样对创业创新寄予如此厚望.李克强总理在2015年政府工作报告中指出:要把"大众创业 ...

  3. Nginx教程(二) Nginx虚拟主机配置

    Nginx教程(二) Nginx虚拟主机配置 1 虚拟主机管理 1.1 Nginx管理虚拟主机 虚拟主机使用的是特殊的软硬件技术,它把一台运行在因特网上的服务器主机分成一台台“虚拟”的主机,每台虚拟主 ...

  4. BattleInfo

    private Dictionary<string, UILabel> mLabels; private Dictionary<string,UISprite> mSprite ...

  5. js继承之原型链继承

    面向对象编程都会涉及到继承这个概念,JS中实现继承的方式主要是通过原型链的方法. 一.构造函数.原型与实例之间的关系 每创建一个函数,该函数就会自动带有一个 prototype 属性.该属性是个指针, ...

  6. python爬虫从入门到放弃(四)之 Requests库的基本使用

    什么是Requests Requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库如果你看过上篇文章关于urllib库的使用,你会发现,其 ...

  7. mysql之 mysqldump 备份恢复详解

    mysqldump是MySQL用于转存储数据库的客户端程序.转储包含创建表和/或装载表的SQL语句 ,用来实现轻量级的快速迁移或恢复数据库,是mysql数据库实现逻辑备份的一种方式. mysqldum ...

  8. Python教程(1.1)——配置Python环境

    在正式开始学习Python之前我们需要先配置好Python环境. Python Python可以从Python官方网站上,选择适合你的操作系统的版本下载.下载完之后,运行下载的可执行文件进行安装. 这 ...

  9. PHP基础入门(二)---入门必备哦!

    前言 在上一章中,我们初步了解了PHP的网页基础和PHP的入门基础,今天继续给大家分享更多有关PHP的知识. 理论知识看起来可能比较枯燥一些,但是我们的实践(敲代码)毕竟离不开它. 只有理论与实践相结 ...

  10. Java泛型学习

    1.泛型的概念 泛型即"参数化类型",就比如我们定义方法的时候,定义一个变量,称为形参,变量值根据传进去的实参的值不同而改变.而泛型的出现,就是为了解决类型也能根据传进去的类型改变 ...