react那些事儿

时间:2023-03-09 17:52:32
react那些事儿

一、参考链接
https://reactjs.org/
http://react-china.org/
https://doc.react-china.org/
https://hulufei.gitbooks.io/react-tutorial/content/index.html
https://github.com/facebook/react/blob/master/CHANGELOG.md
https://github.com/facebook/react/issues
https://discuss.reactjs.org/
https://www.reactiflux.com/

二、调试工具
可以通过安装React Developer Tools for Chrome,来检查是否正确设置了构建过程。
https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi/related

对于开发模式的react站点,chrome工具显示红色背景;对于生产模式的react站点,chrome工具显示黑色背景。

三、运行和安装
1、在线编辑
https://codepen.io/pen?&editors=0010
https://codesandbox.io/s/new

2、本地打开html
不适合在生产环境,因为很慢。demo如下:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World</title>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/babel">

      ReactDOM.render(
        <h1>Hello, world!</h1>,
        document.getElementById('root')
      );

    </script>
    <!--
      Note: this page is a great way to try React but it's not suitable for production.
      It slowly compiles JSX with Babel in the browser and uses a large development build of React.

      To set up a production-ready React build environment, follow these instructions:
      * https://reactjs.org/docs/add-react-to-a-new-app.html
      * https://reactjs.org/docs/add-react-to-an-existing-app.html

      You can also use React without JSX, in which case you can remove Babel:
      * https://reactjs.org/docs/react-without-jsx.html
      * https://reactjs.org/docs/cdn-links.html
    -->
  </body>
</html>

3、cdn引入

A、开发环境

<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

B、生产环境

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

加crossorigin,方便调试,捕获错误。

4、命令行

A、在新应用中安装react(零配置)
https://github.com/facebookincubator/create-react-app

如果安装了node6以上

sudo npm install -g create-react-app
create-react-app mywebapp

cd mywebapp
npm start

如果安装了npm5.2.0以上

npx create-react-app my-app

cd my-app
npm start

B、在老应用中安装react
虽然不用构建管道,也可以搭建react应用,但还是推荐您使用构建管道,它更有效率。
一个现代化的典型构建管道,通常包含包管理器(yarn,npm),打包器(webpack,browsify),编译器(babel)。

npm init
npm install --save react react-dom

为了阻止潜在的问题,react和react-dom版本应该保持一致。

npm install --save-dev babel-preset-react
// .babelrc文件

{
  "presets": ["react"]
}
// main.js

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(
  <h1>Hello, world!</h1>,
  document.getElementById('root')
);

默认情况下,react会包含很多警告,在开发环境,很有用。但是,开发版本的react既大又慢,如果发布应用时,确保用生产版本的react。
如果你的react应用出现性能问题,确保你用了最小的生产版本构建。

四、jsx语法
在react中,不一定要用jsx,es6。react也没有要求一定要用jsx,但是很多人觉得jsx很好用,能够让开发者迅速在js中区分ui和逻辑,babel可以把jsx编译成js。
https://babeljs.io/repl/#?presets=react&code_lz=MYewdgzgLgBApgGzgWzmWBeGAeAFgRgD4AJRBEAGhgHcQAnBAEwEJsB6AwgbgChRJY_KAEMAlmDh0YWRiGABXVOgB0AczhQAokiVQAQgE8AkowAUPGDADkdECChWeASl4AlOMOBQAIgHkAssp0aIySpogoaFBUQmISdC48QA

jsx不是字符串,也不是html,而是js的一种扩展,是React.createElement()的一种语法糖,用于生成react的元素,jsx允许开发者写更多的错误和警告信息。
在jsx中,可以用花括号包含js表达式。用驼峰属性名,比如className。

可以在if,for语句中用jsx,把jsx赋给变量,把jsx作为参数,在函数中返回jsx。
在jsx中嵌入用户输入,很安全。因为react dom在渲染前已经规避了任何值内嵌jsx,一切在渲染前都会被转化成字符串,这有助于阻止xss攻击。

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

React.createElement不仅做了检查,还创建了下面的对象。react的元素是不可变的,一旦被创建,他的子元素和属性都不会变。

const element = {
  type: 'h1',
  props: {
    className: 'greeting',
    children: 'Hello, world'
  }
};

五、状态
1、同步修改状态

this.setState({comment: 'Hello'});

2、异步修改状态

this.setState((prevState, props) => ({
  counter: prevState.counter + props.increment
}));

state是为做交互,数据随时改变而服务的。如果应用是静态的,就不用写state了。

3、setState(updater,callback)

第一个参数可以是对象,也可以是函数;第二个参数是可选的回调函数,通常在setState执行完成并且组件重新渲染后执行。

setState()不会立即更新组件,所以很可能拿不到更新后的state,这时候需要写一个回调或者componentDidUpdate。

六、组件
小项目自顶向下设计,大项目自下而上设计。
接收props,返回react元素。props只读,不能被组件内部修改。

1、纯组件(PureComponent)
一个组件只和props和state有关系,给定相同的props和state就会渲染出相同的结果。
PureReactComponent组件和ReactComponent组件的区别就是它在shouldComponentUpdate中会默认判断新旧属性(props)和状态(state)是否相等,浅比较,如果没有改变则返回false,因此它得以减少组件的重渲染,提升性能。

2、函数式组件(无状态)

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

const element = <Welcome name="Sara" />;
ReactDOM.render(
  element,
  document.getElementById('root')
);

3、类式组件(有状态)

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

类式组件可以给子组件加ref,可以用findDOMNode;
类式组件内可以设置状态和生命周期钩子;
类式组件可以用shouldComponentUpdate控制组件的重渲染;
react把大写开头的标签识别为组件,小写开头的标签识别为html标签。

4、组合组件

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Sara" />
      <Welcome name="Cahal" />
      <Welcome name="Edite" />
    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

5、提取组件
将组件切分成更小的组件,便于全局复用。
6、受控组件
react控制的输入表单元素,比如input,textarea,select,为状态编写事件处理程序。
7、不受控组件
大多数情况下,推荐受控组件来处理表单元素,即state数据驱动视图。偶尔也可以用DOM处理表单,借助ref获取真实的DOM元素,进而获取值。
8、高阶组件(HOC)
高阶组件是一个函数,接收一个组件作为参数,并返回一个新组件。
组件复用,建议用组合而不是用继承实现。

七、生命周期
涉及挂载,更新,卸载,捕获错误等阶段,总共10个方法。

如果是ES5,可以用getDefaultProps获取默认属性,用getInitialState初始化状态,用createClass创建类。

如果是ES6,可以用MyCom.DefaultProps获取默认属性,在constructor中初始化状态,用class关键字创建类。

以下方法需要在继承React.Component的class中使用,ES6语法。
1、挂载阶段
A、constructor(props)
挂载前调用,初始化状态。

B、componentWillMount
挂载前调用,在该方法同步设置状态,不会触发重新渲染。服务端渲染会用到。

C、render
该方法是必须的,不应该改变组件的状态,不直接与浏览器交互,应该保持纯净,每次返回相同的状态。若shouldComponentUpdate()返回false,render()函数将不会被调用。

D、componentDidMount
挂载后调用,在该方法可以发送ajax请求。在该方法设置状态,会触发重新渲染。

2、更新阶段
A、componentWillReceiveProps(nextProps)
挂载阶段,不会调用带有初始属性的该方法,只会在挂载后接收新属性前调用,确保比较新旧属性后,设置状态,重新渲染。因为即便属性没变,react也可能调用该方法重新渲染,所以最好先判断属性是否改变,然后设置状态。

B、shouldComponentUpdate(nextProps, nextState)
初始化渲染时,该方法不会被调用。接收新属性或状态时,在渲染前被调用,默认返回true。如果该方法返回false,表示属性和状态没变,也就不会调用componentWillUpdate(),render()和componentDidUpdate()。
如果shouldComponentUpdate()返回true,setState()永远都会导致重渲。

C、componentWillUpdate(nextProps, nextState)
初始化渲染时,该方法不会被调用。接收新属性或状态时,该方法在渲染前被调用。

D、render
E、componentDidUpdate(prevProps, prevState)
初始化渲染时,该方法不会被调用。组件更新后,会调用该方法,在该方法可以发送ajax请求。

3、卸载阶段
componentWillUnmount
组件被卸载和销毁之前调用,在该方法可以取消定时器,网络请求,清理DOM元素。

4、捕获错误阶段
componentDidCatch(error, info)
react 16中出现错误边界的概念,由于react组件是声明式,而try语句只能用于命令式。错误边界只能捕获子组件的错误,不能捕获自身的错误。

八、优点和缺点
1、react可以不用es6
2、react可以不用jsx
3、创建响应式UI,数据变化时,有效更新和渲染组件。声明视图使代码更容易预测和调试。
4、基于组件,封装组件,管理状态,组合复杂的用户界面。都写在js里面,没有把视图和逻辑进行分离。
5、学一次,写在任何地方。不用考虑旧技术的支持,不用重写已有的代码,就可以在react中开发新特性。
6、可以用node做服务端渲染,用react native做移动端app。
7、react不能用属性选择器

九、答疑解惑
1、可以在js文件中写jsx语法吗?可以在jsx文件中写jsx语法吗?可以在js文件写js语法吗?可以在jsx文件写js语法吗?
都可以,不过,react建议在jsx文件写jsx语法,在js文件写js语法。另外,可以利用编辑器的语法高亮。
2、列表循环
列表循环生成的react的节点,key如果采用索引值,一旦列表新增或删除1条数据,所有节点都会更新,页面性能也会降低。
如果列表有唯一标识,比如id属性,可采用id作为key。
key值建议用唯一的字符串,不要用索引值。

3、判断是否挂载

利用组件的不同生命周期,设置state的值,判断该值即可。

componentDidMount() {
    this.mounted = true;
}

componentWillUnmount() {
    this.mounted = false;
}

4、操作DOM

react提供了refs和findDOMNode。

5、高级组件

谈到react的高级组件,不免会想到组合,继承,Mixins,高阶组件,this.props.children。