react外围概念及其利用

第1章:React入门

1.1 React根底意识

1.1.1 官网材料

React是什么?React是一个申明式,高效且灵便的用于构建用户界面的 JavaScript 库(只关注于View层)。应用 React 能够将一些简短、独立的代码片段组合成简单的 UI 界面,这些代码片段被称作“组件”。

1.1.2 React的特点

  • Declarative 申明式: 以申明式编写UI,让代码更加牢靠且不便调试
  • Component-Based 组件化: 创立领有各自状态的组件,再由组件组成更加简单的UI
  • Learn Once, Write Anywhere 一次学习,随处编写:无论什么技术栈,无需重写现有代码,引入React即可开发新性能,同时还能够进行服务器端渲染
  • 高效: (1)虚构DOM,不间接操作DOM (2)DOM Diff算法,最小化页面重绘
  • 单向数据流: 父子组件采纳props传递数据

1.2 React根本应用

如何将 React 组件增加到现有的 HTML 页面中。你能够基于本人现有的网站,或创立一个空的 HTML 文件来练习。

1.2.1 步骤 1:增加一个 DOM 容器到 HTML

首先,关上你想要编辑的 HTML 页面。增加一个空的 <div> 标签作为标记你想要用 React 显示内容的地位。例如:

<!-- ... 其它 HTML ... --><div id="like_button_container"></div><!-- ... 其它 HTML ... -->

咱们给这个 <div> 加上惟一的 id HTML 属性。这将容许咱们稍后用 JavaScript 代码找到它,并在其中显示一个 React 组件。React 会替换 DOM 容器内的任何已有内容。

1.2.2 步骤 2:增加 Script 标签

接下来,在 </body> 完结标签之前,向 HTML 页面中增加3个 <script> 标签, 前两个标签加载 React。第三个将加载组件代码:

<!-- ... 其它 HTML ... --><!-- 加载 React。--><!-- 留神: 部署时,将 "development.js" 替换为 "production.min.js"。--><script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script><!-- 加载咱们的 React 组件。--><script src="like_button.js"></script>

1.2.3 步骤 3:创立一个 React 组件

在 HTML 页面文件的同级目录下创立一个名为 like_button.js 的文件。在 like_button.js 的底部,退出以下两行代码。

const e = React.createElementconst domContainer = document.querySelector('#like_button_container');ReactDOM.render(e('button',  { onClick: () => this.setState({ liked: true }) },  'Like'), domContainer);

这两行代码会找到咱们在步骤 1 中增加到 HTML 里的 <div>,而后在它外部显示咱们的 React 组件 “Like” 按钮。

1.2.4 步骤 4:应用 React 和 JSX

在下面的示例中,咱们只依赖了浏览器原生反对的个性。这就是为什么咱们应用了 JavaScript 函数调用来通知 React 要显示什么, 然而,React 还提供了一种用 JSX 来代替实现的抉择:

// 显示一个 "Like" <button>return (  <button onClick={() => this.setState({ liked: true })}>    Like  </button>);

在我的项目中尝试 JSX 须要应用到babel, JSX代码所在的<script> 标签须要增加type="text/babel" 属性:

<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

然而这种引入形式不能应用在生产环境中。本节只是一个简略的原生示例,理论中我的项目咱们都是举荐应用集成的工具链来实现最佳的用户和开发人员体验。

1.3 React JSX 以及虚构DOM

1.3.1 虚构DOM概念

  • React提供了一些API来创立“特地”的js对象,如上文利用的React.createElement办法
  • 虚构DOM对象最终都会被React转换为实在的DOM并渲染。咱们在写代码时关注点都在虚构DOM的相干数据上

将一个元素渲染为DOM时,须要一段html申明根节点,而后传入只需把它们一起传入 ReactDOM.render()

// HTML片段,DOM根节点<div id="root"></div>// JS片段const element = <h1>Hello, world</h1>;ReactDOM.render(element, document.getElementById('root'));

render办法的两个参数:纯js或jsx创立的虚构DOM对象,以及用来蕴含虚构DON元素的根节点对象

1.3.2 JSX相干概念

JSX——JavaScript XML,是React定义的一种相似于XML的拓展语法,其作用是用来创立React虚构DOM对象JSX 能够很好地形容 UI 应该呈现出它应有交互的实质模式。JSX 可能会使人联想到模版语言,但它具备 JavaScript 的全副性能。React 并没有采纳将标记与逻辑进行拆散到不同文件这种人为地拆散形式,而是通过将二者独特寄存在称之为“组件”的涣散耦合单元之中,来实现关注点拆散。

const element = <h1>Hello, world!</h1>;

语法规定:

  • 遇到< 结尾的代码,以标签语法解析,html同名标签转换为html同名元素,其余标签须要特地解析,往往是组件
  • 遇到以{结尾的代码,以JS语法解析。
  • 因为 JSX 会编译为 React.createElement 调用模式,所以 React 库也必须蕴含在 JSX 代码作用域内。即便没有显式地调用React及其组件,仍然须要引入它
  • 用户自定义的组件必须的大写字母结尾
  • 一个JSX语法片段只能返回一个根元素,所以必须有外层元素包裹。如果须要返回多个元素,Fragments 容许你将子列表分组,而无需向 DOM 增加额定节点。短语法是<></>

    <React.Fragment>  <td>Hello</td>  <td>World</td>
  • 布尔类型、Null 以及 Undefined 将会疏忽, 以下元素渲染后果雷同

    <div /><div></div><div>{false}</div><div>{null}</div><div>{undefined}</div><div>{true}</div>

    这有助于在特定条件下渲染元素

    <div>  {showHeader && <Header />}  <Content /></div>

    JSX自身也是表达式,在编译之后,JSX 表达式会被转为一般 JavaScript 函数调用,并且对其取值后失去 JavaScript 对象。能够:

  • 在 if 语句和 for 循环的代码块中应用 JSX
  • 将 JSX 赋值给变量
  • 把 JSX 当作参数传入
  • 从函数中返回 JSX

    JSX中能够通过应用引号,来将属性值指定为字符串字面量:

    const element = <div tabIndex="0"></div>;

    因为 JSX 语法上更靠近 JavaScript 而不是 HTML,所以 React DOM 应用 camelCase(小驼峰命名)来定义属性的名称,而不应用 HTML 属性名称的命名约定。

    1.4 模块与组件和模块化与组件化的了解

    1.4.1 模块

  • 了解:向外提供特定JS性能的程序,个别是一个JS文件
  • 为什么须要模块:现代化前端工程,尤其是大型工程,JS代码更多更简单,须要更好的机制去优化开发环节的便当以及生产环节的加载性能
  • 作用:进步JS的复用能力,进步编程效率,进步运行效率

    1.4.2 组件

  • 了解: 组件是用来实现特定性能成果的代码汇合,包含构造、款式与行为(HTML/CSS/JS)
  • 为什么须要组件:古代前端工程中一个界面的性能更加简单,须要进行拆分并关注以后最小单元
  • 作用:进步JS的复用能力,进步编程效率,进步运行效率
  • React的组件分为:(1)继承React的class类组件(2)函数组件

    第2章:React面向组件编程

    2.1 根本了解和应用

    2.1.1 自定义组件

    // 形式一:工厂函数组件const MyFactoryComp = (props) => {return <h1>函数组件</h1>}// 形式二:ES6类组件class MyClassComp extends React.Component {render () {  return <h1>类组件</h1>}}
    // 渲染组件ReactDom.render(<MyFactoryComp />, document.getElementById('root'))

    2.1.2 注意事项

  • 组件名首字母必须大写,没有大写的在援用之前都须要先赋予首字母大写的别名,而后再援用别名
  • 虚构DOM元素只能有一个根元素,如果不不便插入根元素可应用<></>
  • 虚构DOM元素必须有完结标签

    2.1.3 渲染过程

  • React创立外部虚构DOM对象
  • 将其解析为实在的DOM片段
  • 插入到指定元素中,并替换元素下所有内容,所以#root元素节点的内容写了也是有效的

    2.2 组件三大属性之state

    2.2.1 定义及定义方法

    函数组件没有state,类组件才能够保护state,然而函数组件也有本人的hook来进行外部数据管理。类组件中有两种形式申明state并进行初始赋值:

  • class构造函数constructor中进行初始赋值

    class Clock extends React.Component {  constructor(props) {    super(props);    this.state = {date: new Date()};  }  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>    );  }}
  • 间接定义state对象变量

    class Clock extends React.Component {  state = {date: new Date()}  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>    );  }}

    2.2.2 示例

    class Clock extends React.Component {  constructor(props) {    super(props);    this.state = {date: new Date()};  }  componentDidMount() {    this.timerID = setInterval(      () => this.tick(),      1000    );  }  componentWillUnmount() {    clearInterval(this.timerID);  }  tick() {    this.setState({      date: new Date()    });  }  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>    );  }}ReactDOM.render(  <Clock />,  document.getElementById('root'));

    如何了解上述代码的调用程序

    1. 当 <Clock /> 被传给 ReactDOM.render() 的时候,React 会调用 Clock 组件的构造函数。此时第一次更新state
    2. 之后 React 会调用组件的 render() 办法。组件第一次被渲染
    3. 当 Clock 的输入被插入到 DOM 中后,React 就会调用 ComponentDidMount() 生命周期办法。设置 tick() 办法
    4. 每秒都会调用一次 tick() 办法。更新setState(),从新调用 render() 办法
    5. 组件被移除时,调用 componentWillUnmount() 生命周期办法,计时器被移除

      2.2.3 注意事项

  • 不要间接批改state,须要应用setState(),这个函数能够接管一个对象,也能够接管一个函数,构造函数和申明处是惟一能够间接给state赋值的中央
  • state的更新可能是异步的,不能依赖他们的值来更新下一个状态,或者在代码后立刻应用新值做一些事件

    // Correctthis.setState((state, props) => ({  counter: state.counter + props.increment}));
  • state的更新会被合并,当你调用 setState() 的时候,React 会把你提供的对象合并到以后的 state

    2.3 组件三大属性之props

    2.3.1 定义及定义方法

    组件的概念相似于JS函数,该函数能够了解为:入参——即组件标签上的所有属性(attributes)以及子组件(children)转换为单个对象传递给组件,即props,返回值:返回React元素
    在函数组件中,props是写明的惟一参数,在类组件中,props能够在组件外部间接援用

    2.3.2 示例

    // 函数组件举例function Welcome(props) {return <h1>Hello, {props.name}</h1>;}// 类组件举例class Welcome extends React.Component {render() {  return <h1>Hello, {this.props.name}</h1>;}}// 组件调用const element = <Welcome name="Sara" />;ReactDOM.render(element,document.getElementById('root'));

    上例中,name="Sara"属性被赋予了组件,就会被转换为{name: 'Sara'}作为props传递给组件

    2.3.3 注意事项

  • props是只读的,无论是函数组件还是类组件,都不能扭转本身的props,所有组件必须像保护纯函数一样保障props不被批改。

    2.4 组件三大属性之refs

    2.4.1 定义及定义方法

    在某些状况下,你须要在典型数据流之外强制批改子组件。如获取已渲染元素在屏幕上宽高、手动给input聚焦等,React提供了refs来获取实在的DOM。
    refs须要像state一样进行初始赋值

    2.4.2 示例

    Refs 是应用 React.createRef() 创立的,并通过 ref 属性附加到 React 元素。在结构组件时,通常将 Refs 调配给实例属性,以便能够在整个组件中援用它们。

    class MyComponent extends React.Component {constructor(props) {  super(props);  this.myRef = React.createRef(); // 将 Refs 调配给实例属性, 创立一个 ref 来存储 myRef 的 DOM 元素}componentDidMounted () {  // 对该节点的援用能够在 ref 的 current 属性中被拜访  const node = this.myRef.current;  ...}render() {  return <div ref={this.myRef} />;}}

    2.4.3 注意事项

  • 如果一件事件能够通过申明式来实现,那最好不要应用 refs
  • refs 只能在类组件中应用,不能在函数组件中应用,因为它没有实例
  • ref 会在 componentDidMountcomponentDidUpdate 生命周期钩子触发前更新。挂载前,给current属性传入DOM元素,卸载前,传入null元素

    2.5 事件处理

    2.5.1 示例

    class Toggle extends React.Component {constructor(props) {  super(props);  this.state = {isToggleOn: true};  // 为了在回调中应用 `this`,这个绑定是必不可少的  this.handleClick = this.handleClick.bind(this);}handleClick() {  this.setState(state => ({    isToggleOn: !state.isToggleOn  }));}render() {  return (    <button onClick={this.handleClick}>      {this.state.isToggleOn ? 'ON' : 'OFF'}    </button>  );}}ReactDOM.render(<Toggle />,document.getElementById('root'));

    2.5.2 注意事项

  • 通过 onXxx (留神驼峰式)属性指定组件的事件处理函数(函数而非字符串)

    // 原生事件<button onclick="activateLasers()">  Activate Lasers</button>// React事件<button onClick={activateLasers}>  Activate Lasers</button>
  • 不能通过返回 false 的形式阻止默认行为。你必须显式的应用 preventDefault

    function ActionLink() {  function handleClick(e) {    e.preventDefault();    console.log('The link was clicked.');  }  return (    <a href="#" onClick={handleClick}>      Click me    </a>  );}
  • 参数 e 是一个合成事件,并且作为默认第一个参数传递,能够在回调函数内间接调用
  • 须要审慎看待事件回调函数中的 thisclass 的办法默认不会绑定 this,如果函数外部须要调用类组件的 this, 须要显式绑定或者采纳箭头函数申明回调函数

    2.6 组件生命周期

    2.6.1 生命周期定义

    生命周期是组件对象从创立到销毁所经验的特定的生命周期阶段。React组件对象定义了一系列的钩子函数,能够在生命周期的特定时刻执行这些函数。咱们在定义组件中能够重写生命周期钩子函数,达到咱们本人的目标。

    2.6.2 生命周期流程


    进行细分能够分为:

    阶段调用办法
    挂载阶段constructor() / static getDerivedStateFromProps() / render() / componentDidMount()
    更新阶段static getDerivedStateFromProps() / shouldComponentUpdate() / render() / getSnapshotBeforeUpdate() / componentDidUpdate()
    卸载componentWillUnmount()
    错误处理static getDerivedStateFromError() / componentDidCatch()

    2.6.3 注意事项

  • render() 办法是 class 组件中惟一必须实现的办法
  • constructor() 函数中不要调用 setState() 办法, 要防止在构造函数中引入任何副作用或订阅
  • 防止将 props 的值复制给 state
  • componentWillUnmount() 中须要卸载具备副作用的一些办法,比方定时器、勾销网络申请、革除挂载时的订阅等

    2.7 HOOK

    ES6 class 组件能够在外部定义 state 进行数据管理,函数组件当初也有了相似性能的 Hook ,能够在不编写 class 的状况下应用 state 以及其余的React个性。以前咱们说,简单组件用类组件,函数组件只适宜简略组件,有了Hooks撑持之后,函数组件也能够向类组件一样实现更加简单的性能。
    Hook 是一些能够让你在函数组件里“钩入” React state生命周期等个性的函数。其中最罕用的就是 State HookEffect Hook,前者提供了 useState 办法向组件外部增加一些 state ,后者则提供了useEffect办法来模仿 componentDidMountcomponentDidUpdatecomponentWillUnmount 生命周期。

    2.7.1 State Hook

    示例

    // 类组件写法class Example extends React.Component {constructor(props) {  super(props);  this.state = {    count: 0  };}render () {  return (    <>      <button onClick={() => this.setState({ count: this.state.count + 1 })}>        Click me      </button>      <p>You clicked {this.state.count} times</p>    </>  )}}// 函数组件写法import React, { useState } from 'react';function Example() {// 申明一个叫 “count” 的 state 变量const [count, setCount] = useState(0);const [fruit, setFruit] = useState('banana');return <>  <button onClick={() => setCount(count + 1)}>    Click me  </button>  <p>You clicked {count} times</p></>)
  • 引入React中的 useState
  • 通过调用 useState 申明一个 state 变量,该函数返回一对值,通过方括号进行数组解构赋值,咱们定义两个命名变量,第一个解构变量是 state 变量名,第二个解构变量是对该 state 变量进行更新的函数
  • 同类组件中的 state 变量一样,咱们不能间接批改它,须要应用上述第二个解构变量进行间接批改它(如同类组件中的 setState 一样)
  • 函数组件内没有 this ,咱们在援用变量的时候,间接应用上述第一个命名解构变量即可,无需应用 this.Xxx
  • 多个 state 变量能够进行屡次进行申明和调用,与类组件中不同的是,对不同的 state 变量进行更新时,不再是合并,而是间接替换指标变量

    2.7.2 Effect Hook

    示例

    import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState(0);// Similar to componentDidMount and componentDidUpdate:useEffect(() => {  // Update the document title using the browser API  document.title = `You clicked ${count} times`;});return (  <div>    <p>You clicked {count} times</p>    <button onClick={() => setCount(count + 1)}>      Click me    </button>  </div>);}
  • useEffect Hook 有两个参数,第一个参数是一个带有副作用的函数,在DOM更新之后会调用它,即 componentDidMountcomponentDidUpdate 生命周期钩子之后。第二个参数是外部 useState 和函数组件参数——即props 中若干变量组成的数组,如果省略第二个参数,则意味着每次更新渲染之后都会执行这个 useEffect Hook。如果咱们的 useEffect Hook 只依赖于局部变量的批改,能够在数组中订阅它。如果只想在挂载和卸载时执行,传入空数组 [] 就好了。
  • 有些 useEffect Hook 是须要被手动革除的。当订阅内部数据源,革除工作十分重要,能够避免引起内存泄露。WHY???当然是闭包。useEffect Hook 返回一个函数,React 将会在执行革除操作时调用它,相当于 componentWillUnmount 生命周期调用。

    import React, { useState, useEffect } from 'react';function FriendStatus(props) {  const [isOnline, setIsOnline] = useState(null);  useEffect(() => {    function handleStatusChange(status) {      setIsOnline(status.isOnline);    }    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);    // Specify how to clean up after this effect:    return function cleanup() {      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);    };  });  if (isOnline === null) {    return 'Loading...';  }  return isOnline ? 'Online' : 'Offline';}

    2.7.3 其余罕用Hook

  • useCallback
    返回一个 memoized 回调函数。

    const memoizedCallback = useCallback(  () => {    doSomething(a, b);  },  [a, b],);

    把内联回调函数及依赖项数组作为参数传入 useCallback ,它将返回该回调函数的 memoized 版本,该回调函数仅在某个依赖项扭转时才会更新。当你把回调函数传递给通过优化的并应用援用相等性去防止非必要渲染(例如 shouldComponentUpdate )的子组件时,它将十分有用。

  • useMemo
    返回一个 memoized 值。

    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

    把“创立”函数和依赖项数组作为参数传入 useMemo ,它仅会在某个依赖项扭转时才从新计算 memoized 值。这种优化有助于防止在每次渲染时都进行高开销的计算。

  • useReducer
  • useRef
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue
  • 自定义Hook

    2.7.4 注意事项

  • 只在最顶层应用Hook, 不要在循环、条件或嵌套函数中调用Hook
  • 只在React函数中调用Hook,不要在一般的JavaScript函数只能怪调用Hook,能够在React的函数组件中调用或在自定义Hook中调用

    第3章:React利用(基于React脚手架)

    3.1 应用脚手架工具创立React利用

    3.1.1 脚手架介绍

    React官网举荐应用 Create React App 创立一个新的单页利用。如果是大型简单的前端我的项目,咱们也能够本人从0开始搭建——脚手架工具蕴含三大组件:package管理器、打包器、编译器,所以咱们能够用npm + webpack + babel组件本人的工具。
    脚手架工具能够给咱们带来的便当包含:

  • 拓展我的项目和组件的规模,以工程化的思维治理我的项目,模块化、组件化、工程化
  • 蕴含了我的项目所需的根本配置
  • 指定好了根底依赖
  • 提供了一个最简略demo能够间接查看成果
  • 清晰的文件治理目录

    3.1.2 创立我的项目并启动

    Create React App 会配置你的开发环境,以便使你可能应用最新的 JavaScript 个性,提供良好的开发体验,并为生产环境优化你的应用程序。

    npx create-react-app my-appcd my-appnpm start

    3.1.3 了解我的项目构造

    3.2 demo

    第4章:开发中若干要点

    4.1 组件间通信

    4.1.1 形式一:通过props传递

  • 独特的数据放在父组件上,特有的数据放在外部作为 state 保护
  • 通过 props 能够传递个别数据和函数,一层一层传递

    个别数据是由父组件传递给子组件,子组件进行数据读取,而函数常常被用来在子组件中调用并传递数据给父组件。

    4.1.2 形式二:应用音讯公布订阅机制

    能够借助PubSub库来实现

    4.1.3 形式三: Context

    Props 属性是自上而下传递的,但当一个属性是应用程序中许多组件都须要的时候,显式地通过组件树层层传递就显得繁琐,Context 提供了一个无需为每层组件手动增加 props ,就能在组件树间进行数据传递的办法。
    Context 设计目标是为了共享那些对于一个组件树而言是“全局”的数据,例如以后认证的用户、主题或首选语言。
    props 代码示例:

    class App extends React.Component {render() {  return <Toolbar theme="dark" />;}}function Toolbar(props) {// Toolbar 组件承受一个额定的“theme”属性,而后传递给 ThemedButton 组件。// 如果利用中每一个独自的按钮都须要晓得 theme 的值,这会是件很麻烦的事,// 因为必须将这个值层层传递所有组件。return (  <div>    <ThemedButton theme={props.theme} />  </div>);}class ThemedButton extends React.Component {render() {  return <Button theme={this.props.theme} />;}}

    Context 代码示例

    // 应用Context// Context 能够让咱们毋庸明确地传遍每一个组件,就能将值深刻传递进组件树。// 为以后的 theme 创立一个 context(“light”为默认值)。const ThemeContext = React.createContext('light');class App extends React.Component {render() {  // 应用一个 Provider 来将以后的 theme 传递给以下的组件树。  // 无论多深,任何组件都能读取这个值。  // 在这个例子中,咱们将 “dark” 作为以后的值传递上来。  return (    <ThemeContext.Provider value="dark">      <Toolbar />    </ThemeContext.Provider>  );}}// 两头的组件再也不用指明往下传递 theme 了。function Toolbar() {return (  <div>    <ThemedButton />  </div>);}class ThemedButton extends React.Component {// 指定 contextType 读取以后的 theme context。// React 会往上找到最近的 theme Provider,而后应用它的值。// 在这个例子中,以后的 theme 值为 “dark”。static contextType = ThemeContext;render() {  return <Button theme={this.context} />;}}

    注意事项:

  • Context 次要利用场景在于很多不同层级的组件须要拜访同样一些的数据。请审慎应用,因为这会使得组件的复用性变差。

    4.1.4 形式四:Redux

    Redux提供一种全局的应用程序状态管理工具,能够像 vue 中的 vuex 一样不便地治理共享状态。前面会具体介绍。

    4.2 异步申请

    React自身只关注于界面,并不蕴含 ajax 申请,当须要前后台交互时,须要集成第三方 ajax 库。
    axiosfetch 是较为罕用的 ajax 申请库:
    axios : 封装了 XmlHttpRequest 对象的 ajax 的轻量级工具,反对 promise ,浏览器端和服务端均可应用
    fetch : 是新版浏览器反对的原生函数,老版本浏览器并不反对,须要反对老版本的话可增加 fetch.js ,不再应用 XmlHttpRequest 对象提交 ajax

    4.3 ES6及TypeScript

    ES6: 因为React类组件是采纳 ES6 class 定义的,所以咱们须要在一开始就配合 babel 应用。
    当我的项目越来越大时,减少动态类型查看器能够在运行前辨认某些类型谬误。React中提供了 PropTypes 来限定 props 的输出类型,但其实在函数输入输出、 state 治理、接口对立标准等各处都须要进行动态类型查看。
    倡议在大型代码库中应用 FlowTypeScript 来代替,尤其是 TypeScript

    4.4 开源UI组件库

  • material-ui 国外的一款开源react UI组件库
  • ant-design 由国内蚂蚁金服打造的react UI组件库, 次要用于研发企业级中后盾产品,同时提供挪动端版本 ant-design-mobile

    留神:在应用UI组件库时,尽量采纳按需加载的形式打包组件,不要讲UI组件库一次性全盘导入,不利于放大打包体积。

    第5章:react-router

    5.1 基本概念

    5.1.1 react-router 与 react-router-dom

    react-router 是react的一个专门用于实现SPA利用的插件库,基于react的我的项目基本上都会用到此库,它实现了路由的外围性能。目前咱们应用的是 react-router5 的版本。react-router-dom 则是基于 react-router 并退出了在浏览器运行环境下的一些性能,例如 Link 组件、BrowserRouterHashRouter 组件。

    5.1.2 路由分类

    路由是一种映射关系,key 为路由门路, valuefunction/component

  • 后盾路由 服务器路由,valuefunction ,用于解决用户提交的申请并返回响应数据
  • 前台路由 浏览器端路由,value component ,当申请路由path匹配时,界面会更新显示对应的路由,没有产生http申请

    5.1.3 路由组件分类

  • 根组件:BrowserRouter(history模式) 和 HashRouter(hash模式)
    BrowserRouter(history模式) 和 HashRouter(hash模式)作为路由配置的最外层容器,是两种不同的模式,可依据须要抉择。
  • 门路匹配组件: RouteSwitch
  • 导航组件: LinkNavLink

    5.2 history 库

    history 库是 react-router 包的唯二依赖,另一个是react自身。这个库治理浏览器会话历史工具库,有三种模式:

    • browser history, 基于 H5 History Api 封装
    • hash history 基于 window.location.hash 封装
    • memory history 在no-DOM环境中实用,比方RN

    history 对象提供了和 H5 History Api十分类似的属性和办法

  • length
  • action
  • loction( pathname | search | hash | state )
  • push(path, [state])
  • replace(path, [state])
  • go(n)
  • goBack()
  • goForward()
  • block(prompt)

    5.3 react-router 相干API

    5.3.1 路由组件 BrowserRouter 和 HashRouter

    BrowserRouter(history模式) 和 HashRouter(hash模式)作为路由配置的最外层容器,是两种不同的模式,可依据须要抉择。

    // history 模式:class App extends Component {render() {  return (    <BrowserRouter>      <Header />      <Route path='/' exact component={Home}></Route>      <Route path='/login' exact component={Login}></Route>      <Route path='/detail/:id' exact component={Detail}></Route>    </BrowserRouter>  )}}// hash 模式:class App extends Component {render() {  return (    <HashRouter>      <Header />      <Route path='/' exact component={Home}></Route>      <Route path='/login' exact component={Login}></Route>      <Route path='/detail/:id' exact component={Detail}></Route>    </HashRouter>  )}}

    5.3.2 门路匹配组件: Route 和 Switch

  • Route: 用来管制门路对应显示的组件
    参数:
    path: 指定跳转门路
    exact: 准确匹配路由
    component: 路由对应组件
    render: 通过写render函数返回具体的dom或组件
    location: 与以后历史记录地位以外的地位相匹配,则此性能在路由过渡动效中十分有用
    sensitive:是否辨别路由大小写
    strict: 是否配置路由前面的 '/'
  • Switch: 渲染与该地址匹配的第一个子节点 <Route> 或者 <Redirect>。相似于选项卡,只是匹配到第一个路由后,就不再持续匹配

    <Switch>     <Route path='/home'  component={Home}></Route>    <Route path='/login'  component={Login}></Route>     <Route path='/detail' exact  component={detail}></Route>     <Route path='/detail/:id'  component={detailId}></Route>     <Redirect to="/home" from='/' /> </Switch>

    留神上述的 path='/detail/:id',当路由为 /detail/1 时,若不加 exact ,则只会匹配渲染 path='/detail' 路由,增加只会,才会正确地渲染 path='/detail/:id' 路由。

    5.3.3 导航组件: Link 和 NavLink

    LinkNavLink 都能够用来指定路由跳转, NavLink 的可选参数更多。 NavLink 能够看做 一个非凡版本的 Link ,当它与以后 URL 匹配时,为其渲染元素增加款式属性。

    <Link to='/login' activeClassName="selected">  <span>登录</span></Link><NavLinkto="/login"activeStyle={{  fontWeight: 'bold',  color: 'red' }}>  <span>登录</span></NavLink>

    5.3.4 导航组件: Redirect

    <Redirect> 将导航到一个新的地址。即重定向。

    <Switch>   <Route path='/home' exact component={Home}></Route>  <Route path='/login' exact component={Login}></Route>   <Redirect to="/home" from='/' exact /> </Switch>

    下面,当拜访路由 / 时,会间接重定向到 /home
    <Redirect> 常用语用户登录

    class Center extends PureComponent {  render() {      const { loginStatus } = this.props;      if (loginStatus) {          return (              <div>集体核心</div>          )      } else {          return <Redirect to='/login' />      }  }}

    5.3.5 其余

  • withRouter 函数
    withRouter 函数能够将一个非路由组件包裹为 withRouter 高阶路由组件,使这个非路由组件也能拜访到以后路由的 match, location, history 对象。不管组件何时渲染, withRouter 总会将最新的 match, location, history 通过 props 传递给这个被封装的组件。

    import React from "react";import PropTypes from "prop-types";import { withRouter } from "react-router";// A simple component that shows the pathname of the current locationclass ShowTheLocation extends React.Component {  static propTypes = {    match: PropTypes.object.isRequired,    location: PropTypes.object.isRequired,    history: PropTypes.object.isRequired  };  render() {    const { match, location, history } = this.props;    return <div>You are now at {location.pathname}</div>;  }}// Create a new component that is "connected" (to borrow redux// terminology) to the router.const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
  • match 对象
    match 对象蕴含了 <Route> 对以后URL的匹配状况,蕴含以下属性:
    params: 动静路由的 key-value 匹配对
    isExact: 如果精准匹配上了,没有多余的结尾字符,为true
    path: path匹配表达式, <Route> 时有用
    url: url 匹配串, <Link> 时有用

    // 如果获取match对象Route component as this.props.matchRoute render as ({ match }) => ()Route children as ({ match }) => ()withRouter as this.props.matchmatchPath as the return valueuseRouteMatch as the return value
  • location 对象

    {  key: 'ac3df4', // not with HashHistory!  pathname: '/somewhere',  search: '?some=search-string',  hash: '#howdy',
    [userDefined]: true,  }}```   咱们在应用导航组件时,常常用 path 字符串来表述要跳转的地址,但当咱们须要传递额定参数时,location对象就能够发挥作用了。如:```JavaScript// usually all you need<Link to="/somewhere"/>// but you can use a location insteadconst location = {  pathname: '/somewhere',  state: { fromDashboard: true }}<Link to={location}/><Redirect to={location}/>history.push(location)history.replace(location)```

第6章: Redux

6.1 初识Redux

Redux 是专门用于做状态治理的JS库,并不是React的插件库,angular\vue中也能够应用。它能够集中式治理 React 利用的多个组件共享状态。当利用中多个组件须要共享并治理某些状态时,能够用到Redux。比方利用的主题theme治理、音乐类利用的以后歌曲列表治理等。
redux的工作流程如下:

6.2 redux的外围API

6.2.1 createStore()

其作用是创立蕴含指定 reducerstore 对象

import { createStore } from 'redux'import myReducer from 'mypathtoreducer'const store = createStore(myReducer)

6.2.2 store对象

store 是 Redux 库最外围的治理对象,它外部保护 statereducer ,提供 getState() dispatch(action) subscribe(listener) 三个外围办法用于治理状态

6.2.3 applyMiddleware()

applyMiddleware() 是利用于 Redux 的中间件

import { createStore } from 'redux'import thunk from 'redux-thunk' // 以异步中间件为例import myReducer from 'mypathtoreducer'const store = createStore({  myReducer,  applyMiddleware(thunk) // 利用异步中间件})

6.2.4 combineReducers()

combineReducers() 的作用是合并多个 reducer 函数

export default combineReducers({  reducerA,  reducerB  ...})

6.3 redux的三个外围概念

6.3.1 action

action 是要执行的行为对象,蕴含 type 标记属性和行为数据属性,如:

const ADD_POST = 'APP/ADD_POST'const action = {  type: ADD_POST,  payload: {    post: { content: '111' }  }}// 创立 action 的工厂函数会返回一个actionconst addPost = (post) => ({  type: ADD_POST,  payload: {    post: { content: '111' }  }})

6.3.2 reducer

reducer 依据老的 stateaction ,进行解决,并返回新的 state

export default function addPost(initialState = [], action) {  switch (action.type) {    case ADD_POST:      return [].concat(action.payload.post).concat(initialState)    default:      return initialState  }}

6.3.3 store

store 是将 stateactionreducer 分割到一起的对象

import { createStore } from 'redux'import myReducer from 'mypathtoreducer'const store = createStore(myReducer)

store 提供如下api供咱们治理状态:

  • getState() 获取 state
  • dispatch(action) 散发 action , 触发 reducer ,即可改版 state
  • subscribe(listener) 注册监听,当产生新的 state 时主动调用

    6.3.4 redux的问题

    查看示例后,咱们发现:

  • Redux 与 React 组件的代码耦合度太高
  • 编码不够简洁

6.4 react-redux

6.4.1 初始 react-redux

react-redux 是专门用于简化 react 利用中的 redux 应用状况的一个 react 插件库。其将组建分为两类:

  1. UI 组件:只负责从 props 中接收数据并进行 UI 的出现,而不带有任何业务逻辑,不须要应用到 Redux 的API
  2. 容器组件: 负责管理数据和业务逻辑,不负责 UI 的出现,会波及到 Redux 的相干 API

    6.4.2 react-redux 的API

  3. Provider
    让所有被包裹的组件都能够失去state数据

    import { Provider } from 'react-redux'<Provider store={store}>  <APP /></Provider>
  4. connect()
    connect() 办法用于包装 UI 组件生成容器组件

    import { connect } from 'react-redux'export default connect(mapStateToProps, mapDispatchToProps)(Counter)
  5. mapStateToProps()
    将内部的数据(即 state 对象)转换为UI组件的 props 属性,这样在组件外部想要获取 redux 中的 state 时,调用 props 即可
  6. mapDispatchToProps()
    将散发 action 的函数转换为 UI 组件的 props 属性,能够在组件内通过调用 props 办法属性的模式散发 action

    import { connect } from 'react-redux'class Counter extends React.Component {  componentWillMount () {    this.props.onLoad()  }  render () {    let value = this.props.value    return (...)  }}const mapStateToProps = (state) => ({  value: state.value})const mapDispatchToProps = (dispatch) => ({  onLoad: addPost})export default connect(mapStateToProps, mapDispatchToProps)(Counter)

    6.4.3 存在的问题

    Redux 默认是不能进行一步解决的, 当利用中的确须要在 Redux 中执行异步工作时,能够抉择适合的插件来实现,如 saga redux-thunk