react(三)

深入 JSX

从本质上讲,JSX 只是为 React.createElement(component, props, ...children) 函数提供的语法糖。

// JSX代码:
<MyButton color="blue" shadowSize={2}>Click Me</MyButton>
// 编译为:
React.createElement(
  MyButton,
  {color: 'blue', shadowSize: 2},
  'Click Me'
)

如果不存在子节点,你可以使用自闭合(self-closing)格式的标签。

// JSX代码:
<div className="sidebar" />
// 编译为:
React.createElement(
  'div',
  {className: 'sidebar'},
  null
)
ReactDOM.render(
  // <div className='sidebar' />,
  React.createElement(
    'div',
    {className: 'sidebar'},
    null
  ),
  document.getElementById('container')
);

a)指定 React 元素类型

一个 JSX 标签的开始部分决定了 React 元素的类型,首字母大写的标签指示 JSX 标签是一个 React 组件,这些标签会被编译成 命名变量 的直接引用。所以如果你使用 JSX <Foo /> 表达式,那么 Foo 必须在作用域中

React 必须在作用域中。因为 JSX 被编译为 React.createElement 的调用,所以 React 库必须在你 JSX 代码的作用域中

例如,所有的 imports 在这段代码中都是必须的。如果你不使用 JavaScript 打包器,而是通过在 <script> 标签加载 React ,它已经作为一个全局 React 存在。

import React from 'react';
import CustomButton from './CustomButton';
function WarningButton() {
  // return React.createElement(CustomButton, {color: 'red'}, null);
  return <CustomButton color="red" />;
}

b)对 JSX 类型使用点语法

在 JSX 中,你也可以使用点语法引用一个 React 组件。如果你有一个单一模块(module) ,但却导出(exports) 多个 React 组件时,这将会很方便。例如,如果 MyComponents.DatePicker 是一个组件,你可以直接在 JSX 中使用它:

const MyComponents = {
  DatePicker(props) {
    return <div>Imagine a {props.color} datepicker here.</div>;
  }
}
function BlueDatePicker() {
  return <MyComponents.DatePicker color="blue" />;
}

c)用户定义组件必须以大写字母开头

当一个元素类型以小写字母开头,它表示引用一个类似于 <div> 或者 <span> 的内置组件,会给 React.createElement 方法传递 'div' 或者 'span' 字符串。以大写字母开头的类型,类似于 <Foo />,会被编译成 React.createElement(Foo) ,对应于自定义组件或者在 JavaScript 文件中导入的组件。

d)JSX 中的 props(属性)

props(属性) 默认为 “true”

如果你没给 prop(属性) 传值,那么他默认为 true 。下面两个 JSX 表达式是等价的:

<MyTextBox autocomplete />
<MyTextBox autocomplete={true} />

通常情况下,我们不建议使用这种类型,因为这会与ES6中的对象shorthand混淆 。ES6 shorthand 中 {foo} 指的是 {foo: foo} 的简写,而不是 {foo: true} 。这种行为只是为了与 HTML 的行为相匹配。(举个例子,在 HTML 中,<input type="radio" value="1" disabled /> 与 <input type="radio" value="1" disabled="true" /> 是等价的)

e)jsx中的children 

class App extends React.Component {
    render() {
        return (
        <div>
            <h1>{this.props.title}</h1>
            {this.props.children}
</div>
        );
    }
}

ReactDOM.render(
  <App title="编辑供应商">
      <div className="supply">供应商Id: 123</div>
  </App>,
  document.getElementById('root')
);

浏览器渲染结果:

  

使用 PropTypes 进行类型检查

随着应用日渐庞大,你可以通过类型检查捕获大量错误。 要检查组件的属性,你需要配置特殊的 propTypes属性。PropTypes 包含一整套验证器,可用于确保你接收的数据是有效的。

import PropTypes from 'prop-types';
class Greeting extends React.Component {
  render() {
    return (
      <h1>Hello, {this.props.name}</h1>
    );
  }
}
Greeting.propTypes = {
  name: PropTypes.string
};

在这个示例中,我们使用了 PropTypes.string。当你给属性传递了无效值时,JavsScript 控制台将会打印警告。出于性能原因,propTypes 只在开发模式下进行检查

Refs 和 DOM

不要过度使用 Refs:你可能首先会想到在你的应用程序中使用 refs 来更新组件。如果是这种情况,请花一点时间,更多的关注在组件层中使用 state。在组件层中,通常较高级别的 state 更为清晰。

在 DOM 元素上添加 Ref:React 支持给任何组件添加特殊属性。ref 属性接受回调函数,并且当组件 装载(mounted) 或者 卸载(unmounted) 之后,回调函数会立即执行。当给 HTML 元素添加 ref 属性时, ref 回调接受底层的 DOM 元素作为参数

class CustomTextInput extends React.Component {
  constructor(props) {
    super(props);
    this.focus = this.focus.bind(this);
  }
  focus() {
    // 通过使用原生API,显式地聚焦text输入框
    this.textInput.focus();
  }
  render() {
    // 在实例中通过使用`ref`回调函数来存储text输入框的DOM元素引用(例如:this.textInput)
    return (
      <div>
        <input type="text" ref={(input) => { this.textInput = input; }} />
        <input type="button" value="Focus the text input" onClick={this.focus} />
      </div>
    );
  }
}
ReactDOM.render(
  <CustomTextInput />,
  document.getElementById('container')
);

 

优化性能

使用生产版本:如果你在你的 React 应用程序中进行检测性能问题时,确保你正在使用压缩过的生产版本。默认情况下,React包含很多在开发过程中很有帮助的警告。然而,这会导致 React 更大更慢。因此,在部署应用时,请确认使用了生产版本

最好在开发应用时使用开发模式,部署应用时换为生产模式。我们提供压缩好的生产版本的 React 和 React DOM 文件(注意只有结尾为 .min.js 的React文件才是适合生产使用的)。

<script src="https://unpkg.com/react@15/dist/react.min.js"></script>
<script src="https://unpkg.com/react-dom@15/dist/react-dom.min.js"></script>

避免重新渲染:React 构建并维护渲染 UI 的内部表示。它包括你从组件中返回的 React 元素。这些内部状态使得 React 只有在必要的情况下才会创建DOM节点和访问存在DOM节点,因为对 JavaScript 对象的操作是比 DOM 操作更快。这被称为”虚拟DOM”。当组件的 props 和 state 改变时,React 通过比较新返回的元素 和 之前渲染的元素 来决定是否有必要更新DOM元素。当二者不相等时,则更新 DOM 元素。

 

React 顶层 API

React 是 React 库的入口。如果你用 <script> 标签来加载 React,这些顶级 API 都在 React 这个全局变量上。如果你在 npm 下使用 ES6 ,你可以这样写 import React from 'react' 。如果你在 npm 下使用 ES5,你可以这样写 var React = require('react') 。

React 组件允许你将UI拆分为独立的可重用的模块,并且每个模块逻辑也是独立的。 React组件可以通过扩展 React.Component 或 React.PureComponent 来定义

React.Component 是 React 组件使用 ES6 类(classes) 定义时的基类

每个组件都有几个 “生命周期方法” ,前缀为 will 的方法在一些事情发生之前被调用,而前缀为did的方法在一些事情发生后被调用。

constructor(props)

  在 React 组件被装载(mounted)前,该组件的 constructor(构造函数) 将被调用。当实现 React.Component 子类的 constructor(构造函数) 方法时,你应该在其它任何其他语句之前调用 super(props) ,否则,this.props 将在 constructor(构造函数) 中是 undefined(未定义) ,这将导致 bug 。构造函数是初始化 状态(state) 的正确位置。 为此,只需将一个对象分配给this.state ; 不要尝试在构造函数上调用 setState() 。 构造函数也经常用于将事件处理程序绑定到类实例。如果你没有初始化 状态(state) ,并且没有绑定方法,你不需要为你的 React 组件实现一个构造函数。

render()

render()方法是必需的。当被调用时,它会检查 this.props 和 this.state 并返回一个单独的 React 元素。 此元素可以是原生 DOM 组件的表示形式,例如 <div /> ,也可以是你自己定义的另一个复合组件。

componentDidMount()

componentDidMount() 在组件 装载(mounting) 后被立即调用。初始化所需要的 DOM 节点的应该放在这里。 如果你需要从远程加载数据,这是一个实例化网络请求的好地方。

componentWillUnmount()

componentWillUnmount() 在一个组件被 卸载(unmounted) 和 销毁(destroyed) 之前立即被调用。 在此方法中执行任何必要的清理,例如使计时器无效,取消网络请求,或清理在 componentDidMount 中创建的任何 DOM 元素。

setState(updater, [callback])

setState() 排队更改组件的 state ,并通过更新 state 来告诉 React ,该组件及其子组件需要重新渲染。这是用于 响应事件处理程序 和 服务器响应 更新用户界面的主要方法。setState() 总是会导致重新渲染,除非 shouldComponentUpdate() 返回 false 。

第一个参数可以是一个 updater 函数,您也可以随意的传递 一个对象 作为 setState() 的第一个参数。

 

ReactDOM

如果使用 <script> 标签加载 React ,这些在 ReactDOM 上的顶层 API 全局可用。 如果你使用 ES6 与 npm ,你可以写 import ReactDOM from 'react-dom'。如果你使用 ES5 与 npm ,你可以写 var ReactDOM = require('react-dom') 。

React支持所有流行的浏览器,包括 Internet Explorer 9 及更高版本。

ReactDOM.render(
  element,
  container,
  [callback]
)

渲染一个 React 元素到由 container 提供的 DOM 中,并且返回组件的一个 引用(reference)(或者对于 无状态组件 返回 null )。如果 React 元素先前已经被渲染到了 container 中,那么将对其执行更新,并且对 DOM 只修改需要修改的地方,以反映最新的 React元素ReactDOM.render() 控制传入的容器节点的内容。当第一次调用时,容器内部的任何现有DOM元素都会被替换。 之后使用 React 的 DOM diffing 算法来进行有效的更新。ReactDOM.render() 不会修改容器节点(只修改容器的子节点)。

 

DOM 元素

在 React 中,所有 DOM properties 和 attributes(包括事件处理程序)都应该是驼峰命名法命名。 例如,HTML 属性 tabindex 对应于 React 中的 tabIndex 属性。 唯一的例外是 aria-*和 data-* 属性,它们应该是小写。例如,aria-label 就应该是 aria-label,不需要驼峰式命名。

属性中的差异 - 有许多属性在 React 和 HTML 之间有不同的使用方式,如:

className:一般要指定 CSS 类,使用 className 属性。 这适用于所有常规DOM和SVG元素,如 <div> ,<a> 和其他。

style(一般不建议在元素上应用 style 属性。在大多数情况下,应该使用 className 引用外部 CSS 样式表中定义的类。 在 React 应用程序中,经常在渲染时使用 style 来添加动态计算的样式):style 属性接受具有驼峰命名属性的 JavaScript 对象,而不是 CSS 字符串。 这与 JavaScript DOM 的 style 属性一致,但是更高效,并且防止XSS安全漏洞。ms 以外的供应商前缀应以大写字母开头。

<form style={{backgroundColor:'#fff',fontSize:'14px'}} className="search-form"></form>

浏览器渲染结果:

const divStyle = {
  WebkitTransition: 'all', // 注意这里的大写首字母 'W'
  msTransition: 'all' // 'ms' 'ms'是唯一的小写字母的浏览器前缀,大小写均可
};
function ComponentWithTransition() {
  return <div style={divStyle}>This should work cross-browser</div>;
}
posted @ 2018-07-03 18:06  Colorful_coco  阅读(238)  评论(0编辑  收藏  举报