React高级指南
高级指南
1.深入JSX:
从本质上讲,JSX 只是为 React.createElement(component, props, ...children)
函数提供的语法糖。
因为 JSX 被编译为 React.createElement
的调用,所以 React
库必须在你 JSX 代码的作用域中。
import React from 'react'
用户定义组件必须以大写字母开头
当一个元素类型以小写字母开头,它表示引用一个类似于 <div>
或者 <span>
的内置组件,会给 React.createElement
方法传递 'div'
或者 'span'
字符串。以大写字母开头的类型,类似于 <Foo />
,会被编译成 React.createElement(Foo)
,对应于自定义组件 或者在 JavaScript 文件中导入的组件。
JSX 类型不能是表达式
return <components[props.storyType] story={props.story} />; 错误
const SpecificStory = components[props.storyType];
return <SpecificStory story={props.story} />; 正确
JavaScript 表达式作为 props(属性)
你可以传递任何一个用 {}
包裹的 JavaScript 表达式作为 props(属性)。
{1+2+3} 但是 {if(..)else... 和 for(..)} 不是表达式
果你没给 prop(属性) 传值,那么他默认为 true
。下面两个 JSX 表达式是等价的:
<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />
属性扩展
如果你已经有一个 object 类型的 props
,并且希望在 JSX 中传入,你可以使用扩展操作符 ...
传入整个 props 对象。这两个组件是等效的:
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
JSX会删除每行开头和结尾的空格,并且也会删除空行。邻接标签的空行也会被移除,字符串之间的空格会被压缩成一个空格,因此下面的渲染效果都是相同的:
JavaScript 表达式作为 Children(子元素)
通过使用 {}
包裹,你可以将任何的 JavaScript 元素而作为 children(子元素) 传递
Booleans, Null, 和 Undefined 被忽略
在有条件性渲染 React 元素时非常有用。如果 showHeader
为 true
时,<Header />
会被渲染:
<div>
{showHeader && <Header />}
<Content />
</div>
需要注意的是“falsy”值,例如数值 0
,仍然会被 React 渲染。例如,这段代码不会按照你预期的发生,因为当 props.messages
是一个空数组时 0
会被打印:
<div>
{props.messages.length &&
<MessageList messages={props.messages} />
}
</div>
要修复这个问题,确保 &&
之前的表达式总是布尔值:
<div>
{props.messages.length > 0 &&
<MessageList messages={props.messages} />
}
2.使用 PropTypes 进行类型检查
3.静态类型检查
4.Refs 和 DOM
在常规的 React 数据流中,props 是父组件与子组件交互的唯一方式。要修改子元素,你需要用新的 props 去重新渲染子元素。然而,在少数情况下,你需要在常规数据流外强制修改子元素。被修改的子元素可以是 React 组件实例,或者是一个 DOM 元素。在这种情况下,React 提供了解决办法。
何时使用 Refs
下面有一些正好使用 refs 的场景:
- 处理focus、文本选择或者媒体播放
- 触发强制动画
- 集成第三方DOM库
如果可以通过声明式实现,就尽量避免使用 refs 。
在 DOM 元素上添加 Ref
为 类(Class) 组件添加 Ref
Refs 与 函数式组件
5.不受控组件
在大多数情况下,我们推荐使用受控组件来实现表单。在受控组件中,表单数据由 React 组件负责处理。另外一个选择是不受控组件,其表单数据由 DOM 元素本身处理。
要编写一个未控制组件,你可以使用一个 ref 来从 DOM 获得 表单值,而不是为每个状态更新编写一个事件处理程序。
默认值
在 React 渲染生命周期中,表单元素中的 value
属性将会覆盖 DOM 中的 value 。在不受控组件中,你可能希望 React 有初始值,但保留后续更新不受控制。在这种情况下,你需要使用 defaultValue
属性而不是 value
属性。
同样, <input type="checkbox">
和 <input type="radio">
支持 defaultChecked
,而 <select>
和 <textarea>
支持 defaultValue
。
6.优化性能
使用生产版本而不是使用开发版本
避免重新渲染
React 构建并维护渲染 UI 的内部表示。它包括你从组件中返回的 React 元素。这些内部状态使得 React 只有在必要的情况下才会创建DOM节点和访问存在DOM节点,因为对 JavaScript 对象的操作是比 DOM 操作更快。这被称为”虚拟DOM”,React Native 也是基于上述原理。
当组件的 props 和 state 改变时,React 通过比较新返回的元素 和 之前渲染的元素 来决定是否有必要更新DOM元素。当二者不相等时,则更新 DOM 元素。
如果你知道在某些情况下你的组件不需要更新,那么你可以在 shouldComponentUpdate
返回 false
来跳过整个渲染过程,包括在这个组件和后面调用的 render()
。
在大多数情况下,您可以不用手写 shouldComponentUpdate()
,而是从 React.PureComponent
继承。 这相当于用当前和以前 props(属性) 和 state(状态) 的浅层比较来实现shouldComponentUpdate()
。
应用 shouldComponentUpdate
如果你想要你的组件仅当 props.color
或 state.count
发生改变时需要更新,你可以通过 shouldComponentUpdate
函数来检查:
class CounterButton extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
}
shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
在这种情况下,shouldComponentUpdate
函数仅仅检查 props.color
或者 state.count
是否发生改变。如果这些值没有发生变化,则组件不会进行更新。如果你的组件更复杂,你可以使用类似于对 props
和 state
的所有属性进行”浅比较”这种模式来决定组件是否需要更新。这种模式非常普遍,因此 React 提供了一个 helper 实现上面的逻辑:继承 React.PureComponent
。因此,下面的代码是一种更简单的方式实现了相同的功能:
class CounterButton extends React.PureComponent {
constructor(props) {
super(props);
this.state = {count: 1};
}
render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}
大多数情况下,你可以使用 React.PureComponent
而不是自己编写 shouldComponentUpdate
。但 React.PureComponent
仅会进项浅比较,因此如果 props 或者 state 可能会导致浅比较失败的情况下就不能使用 React.PureComponent
。
避免这类问题最简单的方法是不要突变(mutate) props 或 state 的值。例如,上述 handleClick
方法可以通过使用 concat
重写:
handleClick() {
this.setState(prevState => ({
words: prevState.words.concat(['marklar'])
}));
}
7.不使用 ES6
createReactClass({..
8.不使用 JSX
每一个 JSX 元素都是调用 React.createElement(component, props, ...children)
的语法糖,因此,任何你使用 JSX 来做事都可以通过纯 JavaScript 实现。
9.一致性比较(Reconciliation)
React提供声明式API,因此在每次更新中你不需要关心具体的更改内容。这使得编写应用更加容易,但是这样使得你对 React 内部具体实现并不了解,这篇文章介绍了在 React 的 “diffing” 算法中我们所作出地决择,以使得组件的更新是可预测的并且可以适用于高性能应用。
10.Context
在多层级间传递的时候不一定非要死磕属性来一层一层的传,这里介绍一下Context
11.片段(fragments)
动机
一个常见模式是为一个组件返回一个子元素列表。以这个示例的 React 片段为例:
class Table extends React.Component {
render() {
return (
<table>
<tr>
<Columns />
</tr>
</table>
);
}
}
为了渲染有效的 HTML , <Columns />
需要返回多个 <td>
元素。如果 <Columns />
的 render()
函数里面使用一个父级 div ,那么最终生成的 HTML 将是无效的。
class Columns extends React.Component {
render() {
return (
<div>
<td>Hello</td>
<td>World</td>
</div>
);
}
}
在 <Table />
组件中的输出结果:
<table>
<tr>
<div>
<td>Hello</td>
<td>World</td>
</div>
</tr>
</table>
所以,我们介绍 Fragment
。
使用
class Columns extends React.Component {
render() {
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
}
}
在正确的 <Table />
组件中,这个结果输出如下:
<table>
<tr>
<td>Hello</td>
<td>World</td>
</tr>
</table>
简写语法
有一个新的,更短的语法可以用来声明 片段(fragments) 。 它看起来像空标签:
There is a new, shorter syntax you can use for declaring fragments. It looks like empty tags:
class Columns extends React.Component {
render() {
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
}
}
12.插槽(Portals)
ReactDOM.createPortal(child, container)
第一个参数(child
)是任何可渲染的 React 子元素,例如一个元素,字符串或 片段(fragment)。第二个参数(container
)则是一个 DOM 元素。
用法
通常来说,当你从组件的 render 方法返回一个元素时,它将被作为子元素被装载到最近父节点 DOM 中:
render() {
// React 装载一个新的 div,并将 children 渲染到这个 div 中
return (
<div>
{this.props.children}
</div>
);
}
然而,有时候将子元素插入到 DOM 节点的其他位置会有用的:
render() {
// React *不* 会创建一个新的 div。 它把 children 渲染到 `domNode` 中。
// `domNode` 可以是任何有效的 DOM 节点,不管它在 DOM 中的位置。
return ReactDOM.createPortal(
this.props.children,
domNode,
);
}
对于 portal 的一个典型用例是当父组件有 overflow: hidden
或 z-index
样式,但你需要子组件能够在视觉上 “跳出(break out)” 其容器。例如,对话框、hovercards以及提示框:
这包含事件冒泡。一个从 portal 内部会触发的事件会一直冒泡至包含 React tree 的祖先。假设如下 HTML 结构:
13.错误边界(Error Boundaries)
部分 UI 中的 JavaScript 错误不应该破坏整个应用程序。 为了解决 React 用户的这个问题,React 16引入了一个 “错误边界(Error Boundaries)” 的新概念。
错误边界是 React 组件,它可以在子组件树的任何位置捕获 JavaScript 错误,记录这些错误,并显示一个备用 UI ** ,而不是使整个组件树崩溃。 错误边界(Error Boundaries) 在渲染,生命周期方法以及整个组件树下的构造函数中捕获错误。
果一个类组件定义了一个名为 componentDidCatch(error, info):
的新生命周期方法,它将成为一个错误边界:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(error, info) {
// Display fallback UI
this.setState({ hasError: true });
// You can also log the error to an error reporting service
logErrorToMyService(error, info);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
而后你可以像一个普通的组件一样使用:
<ErrorBoundary>
<MyWidget />
</ErrorBoundary>
componentDidCatch()
方法机制类似于 JavaScript catch {}
,但是针对组件。仅有类组件可以成为错误边界。实际上,大多数时间你仅想要定义一个错误边界组件并在你的整个应用中使用。
注意错误边界(Error Boundaries) 仅可以捕获其子组件的错误。错误边界无法捕获其自身的错误。如果一个错误边界无法渲染错误信息,则错误会向上冒泡至最接近的错误边界。这也类似于 JavaScript 中 catch {} 的工作机制。
componentDidCatch 参数
error
是被抛出的错误。
info
是一个含有 componentStack
属性的对象。这一属性包含了错误期间关于组件的堆栈信息。
//...
componentDidCatch(error, info) {
/* Example stack information:
in ComponentThatThrows (created by App)
in ErrorBoundary (created by App)
in div (created by App)
in App
*/
logComponentStackToMyService(info.componentStack);
}
//...
14.Web 组件(Web Components)
React 和 web组件 被用以解决不同问题。Web组件为可重用组件提供了强大的封装能力,而React则是提供了保持DOM和数据同步的声明式库。二者目标互补。作为开发者,你可以随意地在Web组件里使用React,或者在React里使用Web组件,或都有。
个人注:(其实感觉Web组件是React这种组件化库的一个子集)
15.高阶组件(Higher-Order Components)
在React中,高阶组件是重用组件逻辑的一项高级技术。高阶组件并不是React API的一部分。高阶组件源自于React生态。
具体来说,高阶组件是一个函数,能够接受一个组件并返回一个新的组件。
16.与其他库整合(Integrating with Other Libraries)
17.可访问性(Accessibility)
18.代码拆分(Code-Splitting)
参考:
Inheritance with the prototype chain
Inheriting properties
JavaScript objects are dynamic "bags" of properties (referred to as own properties). JavaScript objects have a link to a prototype object. When trying to access a property of an object, the property will not only be sought on the object but on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.
Following the ECMAScript standard, the notation someObject.[[Prototype]]
is used to designate the prototype of someObject
. Since ECMAScript 2015, the [[Prototype]]
is accessed using the accessors Object.getPrototypeOf()
and Object.setPrototypeOf()
. This is equivalent to the JavaScript property __proto__
which is non-standard but de-facto implemented by many browsers.
It should not be confused with the func.prototype
property of functions, which instead specifies the [[Prototype]]
to be assigned to all instances of objects created by the given function when used as a constructor. The Object.prototype
property represents the Object
prototype object.
Here is what happens when trying to access a property:
React高级指南的更多相关文章
- React 高级指南小记
接上篇,还是笔记,还是干货. 深入 JSX 如果使用 JSX 表达式 <Foo />,Foo 必须在范围内,因为这些标签被编译为对指定变量的直接引用. 由于 JSX 编译为对 React. ...
- 【译】高级指南-深入JSX
title: 高级指南-深入JSX date: 2017-4-5 17:13:09 --- 深入JSX 从根本上来讲,JSX 仅仅是提供 React.createElement(component, ...
- Linux网络设置高级指南
from:http://www.oschina.net/question/23734_117144 Linux网络设置高级指南 本文面向的是被Linux复杂的有线无线网络架构弄得头昏脑胀:或者被网上半 ...
- React Native指南汇集了各类react-native学习资源、开源App和组件
来自:https://github.com/ele828/react-native-guide React Native指南汇集了各类react-native学习资源.开源App和组件 React-N ...
- React高级特性
目录: 容器组件 JSX可展开属性 动画 : CSS3 Transition 默认属性 复用代码:mixin 容器组件 React元素也可以包含其他的子元素,这意味着响应的React组件是一个 容器组 ...
- React高级指引
深入JSX 本质上来讲,JSX是为React.createElement方法提供的语法糖 <MyButton color=}> Click Me </MyButton> 编译为 ...
- React高级教程(es6)——(1)JSX语法深入理解
从根本上来说,JSX语法提供了一种创建React元素的语法糖,JSX语句可以编译成: React.createElement(component, props, …children)的形式,比如: & ...
- [Web 前端] React高级教程(es6)——(2)对于Refs最新变动的理解
cp : https://blog.csdn.net/liwusen/article/details/53384561 1.什么是ReactJS中的refs 在React中组件并不是真实的 DOM 节 ...
- 写给移动开发者的 React Native 指南
本文原创版权归 简书 wingjay 所有,如有转载,请于文章篇头位置显示标注原创作者及出处,以示尊重! 作者:wingjay 出处:http://www.jianshu.com/p/b8894425 ...
随机推荐
- Day 08 字符编码
字符编码 计算机基础 启动应用程序 1.双击QQ 2.操作系统接受指定然后把该操作转化为0和1发送给CPU 3.CPU接受指令然后把指令发给内存 4.内存接受指令把指令发送给硬盘获取数据 5.QQ在内 ...
- "SetDestination" can only be called on an active agent that has been placed on a NavMesh. 解决办法
1.设置了 navmesh之后 要bake 也就是烘焙之后 才有效果 2.在unity 中 window->navigation 4.基本上问题应该得以解决:
- Project Euler 18 Maximum path sum I( DP and 记忆化搜索 )
题意:求从三角形顶端出发到达底部,所能够得到的最大路径和 方法一:记忆化搜索 /************************************************************ ...
- [HEOI2013]Eden 的新背包问题
数据极水,不加优化的多重背包都能过...早知道考试的时候不加奇奇怪怪的卡常优化,卡了45分... 就是从前往后做一个多重背包,从后往前再做一个,问的时候就暴力求一下跳过这个的最佳方案... #incl ...
- preload、prefetch的认识
预加载 现在的网络情况虽然很乐观,但是 defer和async 当浏览器碰到 script 脚本的时候: <script src="script.js"></sc ...
- Python 使用matplotlib模块模拟掷骰子
掷骰子 骰子类 # die.py 骰子类模块 from random import randint class Die(): """骰子类""&quo ...
- Java 超类引用子类对象的示例代码
动态方法分配 dynamic method dispatch 一个被重写的方法的调用会在运行时解析,而不是编译时解析 Java 会根据在调用发生时引用的对象的类型来判断所要执行的方法 public c ...
- ubuntu的安装
前言 对计算机的学习来说,使用Linux系统是有好处的,Windows是商业的,无法学习操作系统的内在东西,所以选择折腾Linux. 我选择了ubuntu作为学习系统,Linux发行版没有什么最好之说 ...
- HDU 4686
再不能直视这道题,换INT64就过了....... 同样可以使用矩阵的方法.构造1*5的 D[N],a[n],b[n],a[n]*b[n],1 接着你应该就会了. #include <iostr ...
- linux下測试硬盘读写速度
买了个ssd硬盘,就想着跟普通的机械盘做个比較.由于桌面装的是ubuntu系统,所以就想用linux的命令简单測一下好了 以下是ssd的性能数据: 測试写: xxx@WaitFish:~ > t ...