React入门

目录

1 简介

1.1 React是什么?

1.2 优势

1.3 虚拟DOM原理

实现过程

注意点

2 JSX

jsx语法

特点:

属性值:

注意点:

3 元素

4 组件

4.1 分类

4.2 组件类

4.2.1 简介

4.2.2 组件的props(属性)和state(状态)

4.2.3 组件间的通信

5 React哲学

5.1 开发步骤

5.2 代码分隔

5.2.1 打包

5.2.2 代码分隔

5.2.3 懒加载——React.lazy()

5.2.4 基于路由的代码分隔

6 Context

7 错误处理

7.1 错误边界 Error Boundaries

7.1.1 简介

7.1.2 不适用于以下错误场景

7.1.3 如何使用

7.2 try/catch

8 性能优化

9 严格模式

10 其他

10.1 使用PropTypes进行类型检查

10.2  表单

10.2.1 受控组件

10.2.2  非受控组件


1 简介

1.1 React是什么?

JavaScript库,可用于创建界面;基于Component(组件),所有页面元素都被抽象成组件,大部分操作都是针对组件的。

--》基于组件和虚拟dom原理的js库。

1.2 优势

  1. 组件可复用性和扩展性好,开发效率高;
  2.  不直接操作DOM;
    1. 在虚拟dom中进行计算变化
    2. 将diff反应到真实DOM中,尽可能减少绘制,提高性能
  3.     基于状态实现对DOM控制和渲染。
    1. 是一大创新;
    2. 将组件看成一个状态机;
      1. 一开始有一个初始状态;
      2. 用户互动,导致状态变化;
      3. 触发重新渲染UI。

1.3 虚拟DOM原理

实现过程

  1. React将新的虚拟DOM(由组件的render返回,也就是真实DOM未来要显示的模样)与旧的虚拟DOM(结构、数据与当前真实的DOM一致)做比较,生成差异diff
  2. 将差异diff应用到当前的真实DOM中
  3. 当前真实的DOM更新为新的真实DOM(结构、数据与新的虚拟DOM一致)

React完成全过程,开发者只需要在组件render中返回新的虚拟DOM即可。

注意点

  • 组件是虚拟DOM,不是真实的DOM节点,是存在内存中的一种数据结构。只有它插入文档以后,才会变成真实的DOM节点。
  • 为了与浏览器交互,我们有时候需要用到真实DOM节点,可以通过React.findDOMNode(components)获取组件中的真实DOM
  • React.findDOMNode()只在mounted组件中调用,mounted组件就是已经渲染在浏览器DOM结构中的组件,在组件render()中调用会发生异常,因为此刻是虚拟DOM

2 JSX

 是js的语法扩展。实例:

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

jsx语法

特点:

  1. 在JS中直接使用html标签;
  2. 可用可不用。

属性值:

  1. 值为字符串;
    1. 若在标签内,加“”
    2. 若在标签对内,不加“”
  2. 值为js表达式
    1. 表达式用{}包起来,不加“”
    2. style属性是第一是变量,第二是对象使用,需要两个{{}}
  3. 值为布尔值
    1. 作为表达式处理,需要加{}

注意点:

  1.  使用大小写的约定区分本地组件的类和HTML标签
  2. 某些html为js的保留字,需重新命名
    1. class——className
    2. for——htmlFor
  3.  事件名为驼峰写法
  4. false true null undefined不会被渲染,如果需要使用的化,需转为字符串
<div>My js variable is {String(myVariable)}</div>

3 元素

  • 元素是不可变对象,一旦被创建,就无法更改它的子元素或者属性。
  • 更新UI的方式,就是创建全新的元素,并传入ReactDom.render()中。
  • 但是,React只会更新实际改变的内容

4 组件

4.1 分类

函数组件:编写js函数

 function Welcome(props){
    return <h1>Hello World!</h1>;
}

class组件:继承ES6 React.Component的class

 class Welcome extends React.Component{
    render(){
        return <h1>Hello World!</h1>;
    }
}

两者等效。

4.2 组件类

4.2.1 简介

1.变量声明、引入的外部依赖import;

2.定义组件类class。

生命周期函数

  • constructor //创建期
  • componentWillMount //创建期
  • componentDidMount  //创建期
  • componentWillReceiveProps //特殊状态处理函数,更新期
  • shouldComponentUpdate //更新期
  • componentWillUpdate   //更新期                   
  • componentDidUpdate     //更新期                                                      
  • componentWillUnMount   //销毁期

状态机,随着props和state的改变,DOM表现形式发生变化

  1. 创建期——Mount
    1. constructor:构造函数,可访问this.props和设置初始化state
    2. componentWillMount:组件首次被渲染前调用,可在组件被首次render前最后一次修改state
    3. render:返回虚拟DOM
    4. componentDidMount:组件已在真实DOM中首次渲染后调用,可使用ReactDOM.findDOMNode()获得真实DOM并操作,如为事件绑定监听函数,设置定时器,发送JAX请求
  2. 更新期——Update
    1. componentWillReceiveProps:组件收到新的props调用时,可修改state及决定是否更新props
    2. shouldComponentUpdate:接收到新的props或者state,将要重新渲染前调用,可用于优化react渲染速度,返回true,继续向下执行,返回false停止渲染
    3. componentWillUpdate:shouldComponentUpdate返回true后调用,不能在此处调用setState
    4. render
    5. componentDidUpdate:已在真实DOM中渲染后调用,可操作真实DOM
  3. 销毁期——Unmount
    1. componentWillUnmount:组件在DOM中移除后立刻被调用,此处进行必要的清理

render方法

  • 必须存在的;
  • 返回一个虚拟DOM节点,是一个js对象,返回值可以是null、false或者React组件;
  • 只负责返回虚拟DOM高速React新的DOM的样子;
  •  组件创建期(仅一次)、更新期(可重复)均会被调用,且在更新期,属性(this.props)或者状态(this.state)的变化都有可能触发render被调用;
  • 使用方法的注意点:
    1.  不修改组件属性和状态值
    2. 只能返回一个顶级组件,不能返回一组元素
    3. 不能调用React.findDOMNode()

3.组件输出 export

组件实例化,需要用到ReactDom.render()方法;一般页面中最顶层组件才会使用,将所有组件一起实例化。

4.2.2 组件的props(属性)和state(状态)

  • 组件间的状态传递——props :从父组件到子组件的数据传递
    • 数据流单向——从父到子
    • 当父组件传递的props改变时,React会向遍历整个组件树,并重新渲染使用这个props的组件
    • setProps()只能在组件外调用
    • 组件内部的this.props是只读的
  • 组件内部的状态——state :组件私有,只能在组件内部修改
    • 只用于存储简单的视图状态
    • 可读可改,通过this.state访问和初始化,只能通过setState()修改,且只能在组件内使用
  • 相同点
    • 都是纯JS对象
    • 都会触发render更新
    • 都具有确定性

4.2.3 组件间的通信

  1. 无父子关系的组件间的通信:
    1. 订阅(subscribe)/监听(listen)一个事件通知,并发送(send)/触发(trigger)/发布(publish)/发送(dispatch)事件通知想要的组件
  2. 父组件->子组件:设置props的方式
  3. 子组件->父组件
    1. 回调函数作为子组件的属性
    2. 父组件中定义回调函数,并在父组件render方法中将回调函数作为子组件的属性传递给子组件
    3. 子组件通过该属性向父组件回传数据

注意点:

  1. 自定义组件,首字母必须大写,React将小写字母开头的组件视为原生DOM标签
  2. 组件刷新的顺序
    1. 当组件传给ReactDom.render()时,会调用组件的构造函数,构造函数中有this.state的初始值
    2. React会调用render()方法,确定在页面上展示什么,然后React会更新DOM来匹配组件的渲染输出
    3. 当组件被插入到DOM中后,会调用ComponentDidMount()生命周期方法,调用相关的方法
    4. 通过setState方法计划对UI的更新,React得知state发生变化,会重新调用render()方法进行渲染,react会相应地更新DOM
  3. 状态提升
    1. 多个组件需要反应相同的变化数据,将共同状态提升到最近的共同父组件中去
    2. 按照从上到下的数据流,找到最近的共同父组件
    3. 如果某些数据可以由props或state推导出来,那就不应该存在于state中
    4. 可使用React开发者工具来检查问题组件的props,定位导负责更新state的组件,来定位问题
  4. 类的组合和继承
    1. 组合:React不支持slot概念,可以用props进行传递
<div className="left">
   {props.left}
</div>

<组件 left={<组件  />}/>

             2.继承——尽量不使用

  • Props和组合提供清晰而安全地定制组件外观和行为的灵活方式
  • 组件可以接收任意props,包括基本数据类型、React元素、函数
  • 在组件间复用非UI的功能,建议将其提取为一个单独的JS模块,如函数、对象或类,组件可以直接引入(import)而无需继承

5 React哲学

5.1 开发步骤

  1. 已知设计稿和API数据格式
  2. 将设计好的UI划分为组件层级
    1. 根据单一功能原则来判断组件的范围
    2. 一个组件原则上只负责一个功能
    3. 多个功能,考虑将组件拆分为更小的组件
    4. 父子组件角色确认
  3. 用React创建一个静态版本
    1. 不包含交互功能的UI实现
    2. 通过props传入的数据,不应该使用state构建静态版本
    3. 自上而下或自下而上的构建应用
    4. 当应用比较简单的时候,自上而下更方便
    5. 大型项目,自下而上,并同时为低层组件编写测试
    6. 组件仅只需提供render()方法用于渲染
  4. 确定UI state的最小且完整表示(交互)
    1. 只保留应用所需的可变state的最小集合,其他数据由计算产生
    2. 三个问题判断是否state
      1. 该数据是否由父组件通过props传递而来的?
        1. props
      2. 该数据是否随着时间的推移而保持不变
        1.  否
      3. 能否根据其他state或props计算出该数据
  5. 确定state放置的位置
    1. 哪些组件拥有这些state
    2. 如何确定?
      1. 找到根据这个state进行渲染的所有组件
      2. 找到他们的共同所有者组件
      3. 该共同所有者或则比它层级更高的组件应该拥有该组件
      4. 如果找不到合适的位置来存放该state,可以创建一个新的组件来存放该state,并将该组件置于高于共同所有者组件层级的位置
  6. 添加反向数据流
    1. 处于较低层级的组件更新较高层级的组件中的state

5.2 代码分隔

5.2.1 打包

将一个文件引入并合并到一个单独文件的过程,最终形成一个bundle,接着在页面上引入此bundle,整个应该即可一次性加载
打包前:

// app.js
import { add } from './math.js';
console.log(add(16, 26)); // 42
                        //math.js
export function add(a,b){
    return a+b;
}

打包后:

function add(a,b){
 return a+b;
}
console.log(add(16,26));

5.2.2 代码分隔

为了解决当代码包体积过大,导致加载时间过长的问题;代码分隔能帮助“懒加载”当前用户所需要的内容,能显著提高性能。

方法: import()
分隔前:

import {add} from './math';
console.log(add(16,26));

引入后:

import('./math').then(math=>{
    console.log(math.add(16,26));
})

5.2.3 懒加载——React.lazy()

使用前:

 import OtherComponent from './OtherComponent';

 使用后:

 const OtherComponent = React.lazy(()=> import ('./OtherComponent'));

具体实现过程:

  1. 在组件首次渲染时,自动导入包含otherComponent组件的包
  2. 接收一个函数,这个函数需动态调用import(),返回值为一个Promise,该Promise需要resolve一个default export的React组件
  3. 应在Suspense组件中渲染lazy组件,如此可使用在等待加载lazy组件时做一些loading指示等
function MyComponent() {
  return (
    <div>
        <Suspense fallback={<div>Loading...</div>}>
          <OtherComponent />
       </Suspense>
   </div>
 );
}

fallback属性接收任何在组件加载中想展示的React元素。
可使用ErrorBoundaries技术处理加载异常问题
不支持服务端渲染

5.2.4 基于路由的代码分隔

决定在哪里引入代码分隔。从路由开始(React Rounter路由)

const App = () =>{
    <Router>
      <Suspense></Suspense>
    </Router>
}

6 Context

提供了一个无需为每层组件手动添加props,就能在组件树间进行数据传递的方法

  • 典型的React应用,数据是通过props属性自上而下进行传递的
  • context提供了组件中共享某些属性的方式
  • 全局属性

避免中间层层进行props数据传递。

const ThemeContext = React.createConext('light');//默认值为light
                class App extends React.Component {
    render(){
      return (
        <ThemeContext.Provider value='dark'>
           <Toolbar />   //组件树,使用Provider来将value的值传递给Toolbar这个组件,它的自组件都能拿到这个value的取值
        </ThemeContext.Provider>
      );
   }
}

function Toolbar(props){//中间组件不需要明确传递theme的取值
   return (
    <div><ThemeButton /></div>
   );
}

class ThemeButton extends React.Component{
    static contextType = ThemeContext;//读取当前的theme context,React会向上查找到最近Provider,然后使用它的值,即‘dark’
    render(){
        return <Button theme={this.context}></Button>
    }
}


7 错误处理

7.1 错误边界 Error Boundaries

7.1.1 简介

  • 是一种React组件。
  • 可以捕获并打印发生在其子组件树上发生的js错误,并会渲染出备用UI
  • 在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误
  • 工作方式类似js中的catch{},但是只针对class组件

7.1.2 不适用于以下错误场景

  • 事件处理
  • 异步代码,setTimeout或requestAnimationFrame回调函数
  • 服务端渲染
  • 它自身抛出来的错误

7.1.3 如何使用

class组件中定义了static getDrivedStateFromError() 或componentDidCatch()这两个生命周期方法中的任何一个,它就变成了一个错误边界

  1.  使用static getDrivedStateFromError()用了渲染备用UI
  2.  componentDidCatch打印错误信息

当作常规组件去使用即可。


7.2 try/catch

仅用于命令式代码,处理事件处理的错误。

try{
 showButton();
} catch(error){}

8 性能优化

  1. 使用生产版本:非生产版本默认包含了很多警告信息,使得变大变慢
  2. 避免重复渲染
    1. 重写shouldComponentUpdate来进行优化,默认返回true,让React执行更新。当明确知道何时不需要更新,可以在shouldComponentUpdate返回false来跳过渲染,包括render的调用及之后的操作
    2. 继承React.PureComponent,实现浅比较,当props和state的所有字段发生变化时,进行渲染
      1. 当props或者state某种程度是可变的话,浅比较会有遗漏,不适合用此方式
      2. 浅比较,当对比的类型为object,且key长度相等时,浅比较仅仅是用Object.is()对它的value做了基本数据类型的比较,所有key里面是对象的话,会出现比较结果不正确的情况
    3. 避免更正用于props或state的值
  3. Profiler:分析渲染的代价(工具)

9 严格模式

是用来突显应用程序中潜在问题的工具。

不会渲染任何可见UI,为其后代元素触发额外的检查和警告。

使用方式:

<div>
    <Header>
    <React.StrictMode>
        <div><ComponentOne /><ComponentTwo/></div>
    </React.StrictMode>
    </Header>
</div>

仅对ComponentOne和ComponentTwo及其后代元素进行检查
检查内容:

  • 识别不安全的生命周期
  • 使用过时的字符串ref API警告
  • 使用废弃的findDomNode 方法的警告
  • 检测意外的副作用
  • 检测过时的context api

10 其他

10.1 使用PropTypes进行类型检查

import PropTypes from 'prop-types';

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

Greeting.propTypes =  {
    name : PropTypes.string //指定name为string
}

指定name为string
优化Flow或TypeScript=>静态类型检查器
默认值:

 Greeting.defaultProps ={
  name : 'stranger'
};

10.2  表单

10.2.1 受控组件

被React以state方式控制取值的表单输入元素叫做受控组件。

render(){
    return ({
       <form onSubmit={this.handleSubmit}>
           <label>
               名字:
               <input type="text" value={this.state.value} onChange={this.handleChange}/>
           </label>
             <input type="submit" value="提交"/>
       </form>
    });
}

10.2.2  非受控组件

表单数据将由Dom节点来处理,使用ref来从DOM节点中获取表单数据。

constructor(props){
  super(props);
  this.input = React.createRef();
}


render(){
    return ({
      <form onSubmit={this.handleSubmit}>
        <label>
         名字:
          <input type="text" ref={this.input} />
        </label>
         <input type="submit" value="提交"/>
      </form>
   });
}

 优点:代码量少

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值