React从0到1系列第二章——React的使用方式和基础API介绍

1、React简介

由于以前作了挺久的Vue开发。如今开始学习React也是并不难的。首先要对React的总体脉络要有个大概的了解。(注:这里只作学习的记录和总结,有些可能会遗漏,后期有了新的感悟也会慢慢完善,一些基础的语法的使用仍是要看官方网站为主)。javascript

从上图能够得知React分为三大致系:css

  1. React.js
  2. ReactNative
  3. ReactVR

学习的顺序也是React.js->ReactNative->ReactVR按部就班的。html

React的基础大致包括下面这些概念:

  1. 组件
  2. JSX
  3. Virtual DOM
  4. Data Flow

React.js不是一个框架,它只是一个库。它只提供 UI (view)层面的解决方案。在实际的项目当中,它并不能解决咱们全部的问题,须要结合其它的库,例如 ReduxReact-router 等来协助提供完整的解决方法。前端

2、React开发环境的搭建

2.一、在浏览器中编写React

<!DOCTYPE html>
<html> <head>  <meta charset="UTF-8">  <!--https://cdnjs.com/-->  <script src="./js/react.development.js"></script>  <script src="./js/react-dom.development.js"></script>  <script src="./js/browser.min.js"></script>  <script src="./js/prop-types.min.js"></script> </head> <body>  <div id="root"></div>  <!--凡是使用 JSX 的地方,都要加上 type="text/babel"-->  <script type="text/babel">  class Hello extends React.Component {  render() {  return (<h1>Hello,{this.props.name}</h1>)  }  }  ReactDOM.render(  <Hello name="zhangsan" />,  document.getElementById('root')  );  </script> </body> </html> 复制代码

上面代码一共用了四个库:react.jsreact-dom.jsbrowser.jsprop-types.min.js,它们必须首先加载。vue

  1. react.jsReact的核心库。
  2. react-dom.js:负责 Web页面的 DOM操做。
  3. browser.js:将 JSX语法转为 JavaScript语法。
  4. prop-types.min.js:是传入的 props类型的验证。自 React v15.5起, React.PropTypes已移入另外一个包中,使用 prop-types库代替。

须要注意的是从Babel 6.0开始,再也不直接提供浏览器直接编译的JS版本,而是要用构建工具构建出来。这里只作演示用。建议学习开发的时候也不要使用浏览器直接引入的方式。java

2.二、 搭建本地开发环境

  1. 安装 node.js
  2. 安装 npm
  3. 全局安装官方推荐脚手架工具 create-react-app,相似于 Vuevue-cli
npm install -g create-react-app
// 在任意文件夹中使用create-react-app新建项目 create-react-app demo 复制代码

安装成功以后,npm start 或者 yarn start就能够启动项目了。node

create-react-app生成的目录结构以下:react

demo/
 README.md  package.json  yarn.lock  .gitignore  node_modules/  public/  favicon.ico  index.html  ...  src/  App.css  App.js  App.test.js  index.css  index.js  logo.svg  serviceWorker.js 复制代码

package.json安装的React依赖介绍以下:webpack

package.jsondependencies能够看出来脚手架工具默认安装了React须要的依赖。下面就介绍这些核心依赖的做用:git

  1. react:是 React的核心库。
  2. react-dom:负责 Web页面的 DOM操做。
  3. react-scripts:生成项目全部的依赖。例如 babelcss-loader, webpack等从开发到打包前端工程化所须要的 react-scripts都帮咱们作好了。

如今就能够在App.js里编写咱们本身的代码了,以下(已修改生成的源码):

在项目根目录执行npm start(若安装了yarn可以使用yarn start),打开http://localhost:3000就能够看到首页了:

建议你们参考Create React App 中文文档

3、Virtual DOM 介绍

要想理解JSX的由来,就要先介绍一下Virtual DOM

一个真实页面对应一个DOM树。在传统页面的开发模式中,每次须要更新页面时,都要手动操做DOM 来进行更新。DOM操做很是昂贵。并且这些操做DOM的代码变得难以维护。

React把真实DOM树转换成JavaScript对象树,也就是Virtual DOM。以下图:

每次数据更新后,从新计算Virtual DOM,并和上一次生成的Virtual DOM作对比,对发生 变化的部分作批量更新。VirtualDOM不只提高了React的性能,并且它最大的好处其实还在于方便和其余平台集成(好比react-native是基于Virtual DOM渲染出的原生控件)。

所以在Virtual DOM输出的时候,是输出Web DOM,仍是Android控件,仍是iOS控件,由平台自己决定。

3.一、DOM 元素

Web页面是由一个个HTML元素嵌套组合而成的。当使用JavaScript来描述这些元素的时候,这些元素能够简单地被表示成纯粹的JSON对象。好比,咱们如今须要描述一个按钮(button),用HTML 语法表示很是简单:

<button class="primary">
 <em>submit!</em> </button> 复制代码

其中包括了元素的类型和属性。若是转成JSON对象,会包括元素的类型以及属性:

{
 type: 'button',  props: {  className: 'primary',  children: [{  type: 'em',  props: {  children: 'submit'  }  }]  } } 复制代码

上面的JS对象表达了一个按钮功能。在表达还不怎么复杂的结构时,书写就已经很难受了。这让咱们想起使用HTML编写结构时的简洁。因此JSX语法为此应运而生。假如咱们使用JSX 语法来从新表达上述button元素,只需下面这么写:

ReactDOM.render(
 <button className="primary">  <em>submit!</em>  </button>  , document.getElementById('root')) 复制代码

4、JSX介绍

JSXHTML语法直接加入到JavaScript代码中,会让代码更加直观并易于维护。经过编译器转换到纯JavaScript后由浏览器执行。JSX在产品打包阶段都已经编译成了纯JavaScript

注意:JSXJavaScript语言的一种语法扩展,长得像HTML,但并非HTML。尽管JSX是第三方标准,但这套标准适用于任何一套框架。如今已所有采用BabelJSX编译器来实现对JSX语法的编译。

class Test extends React.Component {
 constructor(props) {  super(props)  }  render() {  return (  <div>  <h1 className='title'>Hello,React</h1>  </div>  )  } } ReactDOM.render(<Test />, document.getElementById('root')) 复制代码

上面的代码通过编译之后会变成以下:

class Test extends React.Component {
 constructor(props) {  super(props)  }  render() {  return (  React.createElement(  'div',  null,  React.createElement(  'h1',  { className: 'title' },  'Hello,React'  )  )  )  } } ReactDOM.render(<Test />, document.getElementById('root')) 复制代码

React.createElement会构建一个JavaScript对象来描述HTML结构的信息,包括标签名、属性、还有子元素等。这样的代码就是合法的JavaScript代码了。

因此从JSX到页面通过了以下图的过程:

4.一、使用 HTML 标签

ReactDOM.render(<div className="foo">Hello</div>, document.getElementById('root'))
复制代码

HTML里的classJSX里要写成className,由于classJS 里是保留关键字。同理某些属性好比for要写成htmlFor

4.二、使用 JavaScript 表达式

JSX遇到HTML标签(以<开头),就用HTML规则解析。遇到代码块(以 { 开头),就用 JavaScript规则解析。

const names = ['zhangsan', 'lisi', 'wangwu']
ReactDOM.render(  <div>  {  names.map((name,key) => {  return <div key={key}>Hello,{name}</div>  })  }  </div>,  document.getElementById('root') ) 复制代码

JSX容许直接在模板插入JavaScript变量。若是这个变量是一个数组,则会展开这个数组的全部成员。

const names = [<div key="1">zhangsan</div>, <div key="2">lisi</div>]  ReactDOM.render(  <div>  {names}  </div>,  document.getElementById('root') ) 复制代码

4.三、 注释

JSX里使用注释也很简单,就是沿用JavaScript,惟一要注意的是在一个组件的子元素位置使用注释要用 {} 包起来。

const App = (
 <Nav>  {/* 节点注释 */}  <Person  /* 多行  注释 */  name={window.isLoggedIn ? window.name : ''}  />  </Nav> ) 复制代码

4.四、 HTML转义

React会将全部要显示到DOM的字符串转义,防止XSS。因此若是JSX中含有转义后的实体字符好比 &copy (©) 最后显示到 DOM中不会正确显示,由于React自动把&copy中的特殊字符转义了。可使用dangerouslySetInnerHTML来实现。

ReactDOM.render(
 <div dangerouslySetInnerHTML={{ __html: '&copy 2020' }} />,  document.getElementById('root') ) 复制代码

4.五、自定义 HTML 属性

若是在JSX中使用的属性不存在于HTML的规范中,这个属性会被忽略。若是要使用自定义属性,能够用data-前缀。可访问性属性的前缀aria-也是支持的。

ReactDOM.render(<div data-attr="abc">content</div>, document.getElementById('root'))
复制代码

5、组件化

React认为组件是和模板紧密关联的,组件模板和组件逻辑分离让问题复杂化了。React 容许将代码封装成组件(component),而后像插入普通 HTML 标签同样,在网页中插入这个组件。一个React应用就是构建在React 组件之上的。Component(组件)能够是类组件(class component)、函数式组件(function component)。

组件有三个核心概念,React组件基本上由组件的构建方式组件内的属性状态生命周期方法组成。以下图:

  • props(属性)
  • states(状态)
  • 生命周期方法

注意:组件生成的 HTML 结构只能有一个单一的根节点。在React中,数据是自顶向下单向流动的,即从父组件到子组件。

5.一、组件构建方法

官方在React组件构建上提供了3种不一样的方法:React.createClassES6 classes 和无状态 函数(stateless function)。

官方在React@15.5.0后不推荐用React.createClass,建议使用ES6 class,这里不作具体介绍。

ES6 classes

class Test extends React.Component {
 constructor(props) {  super(props)  }  render() {  return (<h1>Hello,React</h1>)  } } 复制代码

无状态组件

能够用纯函数来定义无状态的组件(stateless function),这种组件没有状态,没有生命周期,只是简单的接受props渲染生成DOM结构。无状态组件很是简单,开销很低。好比使用箭头函数定义:

const Hello = (props) => <div>Hello {props.name}</div>
 ReactDOM.render(<Hello name="张三" />, document.getElementById('root')) 复制代码

5.二、props

props就是组件的属性,由外部经过JSX属性传入设置,一旦初始设置完成,就能够认为this.props 是不可更改的,因此不要轻易更改设置this.props里面的值。

class Hello extends React.Component {
 constructor(props) {  super(props)  }  render() {  return (  <h1>Hello,{this.props.name}</h1>  )  } }  // PropTypes 验证,若传入的props type不是string将提示错误 Hello.propTypes = {  name: PropTypes.string }  // Prop 初始值,若是 prop 没有传入值將會使用 default 值 lisi Hello.defaultProps = {  name: 'lisi' }  ReactDOM.render(<Hello name="张三" />, document.getElementById('root'))  复制代码

5.三、state

state是组件的当前状态,用this.state来存取state。一旦状态(数据)更改,组件就会自动调用 render从新渲染UI,这个更改的动做会经过this.setState方法来触发。

下面代码是一个1000毫秒就會加一的累加器:

class Timer extends React.Component {
 constructor(props) {  super(props)  // 须要自行绑定 this context  this.tick = this.tick.bind(this)  this.state = {  count: 0  }  }  // 累加器方法,每一秒会使用 setState() 更新内部 state,让 Component 从新 render  tick() {  this.setState({ count: this.state.count + 1 })  }  // 生命周期函数  componentDidMount() {  this.interval = setInterval(this.tick, 1000);  }  // 生命周期函数  componentWillUnmount() {  clearInterval(this.interval);  }  render() {  return (  <div>Count: {this.state.count}</div>  )  } } ReactDOM.render(<Timer />, document.getElementById('root')) 复制代码

5.四、生命周期方法

每一个组件都包含都包含组件生命周期方法,在运行过程当中特定的阶段执行这些方法。

组件的生命周期分为四类,共有10个方法:

  1. 挂载
  2. 更新
  3. 卸载
  4. 错误处理

下面会依次介绍这几类组件的生命周期所调用的函数。

挂载

当组件实例被建立并插入DOM中时,其生命周期调用顺序以下:

  • constructor()
  • static getDerivedStateFromProps():会在调用 render方法以前调用,而且在初始挂载及后续更新时都会被调用。
  • render():是 class组件中惟一必须实现的方法。
  • componentDidMount():在组件挂载后(插入 DOM树中)当即调用。

更新

当组件的propsstate发生变化时会触发更新。组件更新的生命周期调用顺序以下:

  • static getDerivedStateFromProps()
  • shouldComponentUpdate():当 propsstate发生变化时, shouldComponentUpdate() 会在渲染执行以前被调用。
  • render()
  • getSnapshotBeforeUpdate():在最近一次渲染输出(提交到 DOM节点)以前调用。
  • componentDidUpdate():会在更新后会被当即调用。首次渲染不会执行此方法。

卸载

当组件从DOM中移除时会调用以下方法:

  • componentWillUnmount():在组件卸载及销毁以前直接调用。

错误处理

当渲染过程,生命周期,或子组件的构造函数中抛出错误时,会调用以下方法:

  • static getDerivedStateFromError():今生命周期会在后代组件抛出错误后被调用。
  • componentDidCatch():今生命周期在后代组件抛出错误后被调用。

这里只作简单介绍,后面会单独写文章详细记录生命周期的使用方式。

6、事件处理

React里面绑定事件的方式和在HTML中绑定事件相似,使用驼峰式命名指定要绑定的onClick属性为组件定义的一个方法。下面是一个数字累加的小例子:

class AddCount extends React.Component {
 constructor(props) {  super(props)  this.state = {  count: 0  }  }  handleClick(e) {  this.setState({ count: this.state.count + 1 });  }  render() {  return (  <div>  <p>Count: {this.state.count}</p>  <button onClick={this.handleClick.bind(this)}>Click me</button>  </div>  )  } } ReactDOM.render(<AddCount />, document.getElementById('root')) 复制代码

注意要显式调用bind(this)将事件函数上下文绑定要组件实例上,这也是React推崇的原则:没有黑科技,尽可能使用显式的容易理解的JavaScript代码。

7、 DOM操做

有时候咱们避免不了要直接操做DOMReact也提供了几种咱们能够直接操做DOM的方式。

findDOMNode

当组件加载到页面上以后(mounted),能够经过react-dom提供的findDOMNode()方法拿到组件对应的DOM元素。

class Test extends React.Component {
 constructor(props) {  super(props)  }  componentDidMount() {  const el = ReactDOM.findDOMNode(this)  // 123456  console.log(el.textContent)  }  render() {  return (  <div>123456</div>  )  } } ReactDOM.render(<Test />, document.getElementById('root')) 复制代码

注意:findDOMNode() 不能用在无状态组件上。findDOMNode 仅在组件始终返回永不更改的单个 DOM 节点时才起做用。在<React.StrictMode>严格模式下,这个方法已经被官方弃用,因此在开发中不要使用这个方法。

Refs

另一种方式就是经过在要引用的DOM元素上面设置一个ref属性指定一个名称,而后经过 this.refs.name来访问对应的DOM元素。

class Test extends React.Component {
 constructor(props) {  super(props)  }  componentDidMount() {  this.refs.textInput.focus()  }  render() {  return (  <div>  <input ref="textInput" />  </div>  )  } } ReactDOM.render(<Test />, document.getElementById('root'))  复制代码
  1. 不要在 render或者 render以前访问 refs
  2. 不要滥用 refs。好比只是用它来按照传统的方式操做界面 UI:找到 DOM -> 更新 DOM

参考

https://zh-hans.reactjs.org/

http://huziketang.mangojuice.top/books/react/

https://www.bilibili.com/video/BV1g4411i7po?p=2

https://www.jianshu.com/p/c6040430b18d

https://www.zhihu.com/question/336664883/answer/790855896

https://book.douban.com/subject/26918038/

https://www.kancloud.cn/digest/babel/217110

http://www.ruanyifeng.com/blog/2015/03/react.html

https://kdchang.gitbooks.io/react101/content/

https://github.com/mocheng/react-and-redux/issues/99

https://juejin.im/entry/587de1b32f301e0057a28897

https://www.html.cn/create-react-app/docs/getting-started/

本文使用 mdnice 排版

相关文章
相关标签/搜索