react官方文档学习笔记

351 阅读8分钟

前言

react是一种声明式、用于构建用户界面的javascript库。

features

  • 组件化 React.Component
	class ShoppingList exteds React.Component {
    render() {
    //jsx语法(对渲染内容的轻量级描述) react元素 js对象,可以用于参数传递或者变量使用  === React.createElement(); ReactDOM.render(jsx,dom)
    	return (
        	//xxx
            //{this.props.xxx}
            //onClick={function() {
            	xxx
            }
        ) 
    
    }
    }
  • props属性传值
  • 交互 onClick
  • 状态 state
	构造函数中初始化state
    constructor(props) {
    	super(props);
        this.state = {
        	//私有属性
        }
    }
    更改state
    this.setState({//});
  • 状态提升

将自组价中的状态提升到共同的父组件中进行保存,实现组件的状态数据共享。子组件中不在持有state,从父组件中接收值并且通知父组件更新state,称之为受控组件。

  • 事件监听属性on[Event],事件处理handle[Event]
  • 不可变性

不直接修改或者改变底层数据,简化复杂的功能。

跟踪数据的变化,直接修改数据会使得跟踪数据的变化变得非常的困难。shouldComponentUpdate

创建 pure组件,可以确实不可变属性何时发生改变,组件何时渲染。

  • 函数式组件

只有render,没有state

	function Square(props) {
    	return (
        	//
        );
    }
  • 练习demo

井字棋、时间旅行

  • react元素是javascript一等公民中的对象(first-class javascript objects)
  • 动态更新列表时指定一个合适的key,在当前的同一级元素中保持唯一。
  • 不能通过this.props.key获取

jsx

标记和组件放在组建中

关注点分离

	1.使用字符串标识字符串字面量propName="propValue"
    2.可以防止注入攻击xss(cross-site-scripting),渲染内容前会先进行转义,变成字符串
    3.babel会将jsx转成一个React.createElement()函数调用
    {
    	type:xx,
        props: {
        	xx:xx
        }
    }
    4.元素是构成react应用的最小砖块
    将react元素渲染到根节点DOM中  使用ReactDOM.render(element,document.getELementById("root"))
    5.React元素是不可变对象 只会更新实际变化的内容

组件与属性

独立可复用的代码片段

函数组件和class组件

	function Xxx(props) {
    	return xxx;
    }
    //本质上是一个javascript函数
    
    //es6的class定义组件
    class Xxx extends React.Component {
    	render() {
        	retuern xxx;
        }
    }
    <Xxx /> //大写字母开头

组合组件 function APP (props) { return (

); } 拆分组件 拆分成更小的组价

Props只读性,不可以更改自身的属性 React的组件都是类似于纯函数不能更改props

state与生命周期

state是组件的私有属性 不能直接修改 构造函数中赋值初始化 state的更新是异步的 浅合并 this.setState((state,props) => ({ xx:state.xx + props.xx }))

componentDidMount 组件挂载 componentWillUnmount 组件卸载

数据是向下流动的 单向 瀑布

事件处理

  • 命名是小驼峰
  • {this.fn}
  • 显示调用e.preventDefault()阻止默认行为
  • 回调函数绑定this this.fn = this.fn.bind(this)
	1.
	fn = () => {
    	//xxx
    }
	{this.fn}
    2.
    fn() {
    	//
    }
    {() => this.fn()}
    3.传参
    {(e) => this.fn(xx,e)}
    {this.fn.bind(this,xx)}

条件渲染

  • 根据应用的状态渲染对应状态下的不同的内容 if
  • 使用元素变量存储元素
  • 与运算符 &&

在{}中使用实现条件渲染

  • 使用三目运算符实现条件渲染
  • 阻止组件渲染

render方法返回null 不影响组件的生命周期


列表和key

key用于告诉react哪些元素改变了
key的信息传给react 组件无法使用
使用map生成列表


表单

受控组件

  • 自己维护state
	input textarea select
  • form
	onSubmit
    onchange

状态提升

将反应相同变化的共享的状态提升到最近的共同父组件中


组合与继承

推荐使用组合实现代码的复用

使用{props.children}将子组件传递到渲染结果中

自定义 {props.left} left= {} 使用props传递 类似于“槽”的概念

props可以接收任意类型


react的设计哲学

  • 组件
  • 单一功能
  • 先实现一个静态版本,不考虑太多的交互
  • ui state的最小表示(完整)、
  • 确定state放置的位置
  • 添加反向数据流

无障碍

aria-*

语义化的html

	<Fragment>
    //xxx
    </Fragment>
    段语法:
    <>
    //xxx
    </>

无障碍的表单

	htmlFor

控制焦点

	React.createRef()
    使用ref控制组件
    使用forwardRef向子组件转发ref

代码分割

  • 打包
将文件引入并合并成一个单独的文件,形成一个bundle
  • 创建多个包,运行时动态加载
使用动态import 
import(xx).thne(xx => {
	//xx
})
babel-plugin-sync-dynamic-import
  • 懒加载
	React.lazy(() => import())
    <Suspense fallback={xx}></Suspense>
  • 异常捕获边界error boundary
  • 基于路由的代码分割
	1.使用react-router-dom

context

无需添加props,实现组件树直接的数据传递 应用中共享的全局的数据

const ThemeContext =  React.creatContext('xxx')
<ThemeContext.provider value="xxx"></ThemeContext.provider> //provider组件 下面的组件都可以使用 从最近匹配到的provider去获取数据 设置xxx.contextType = ThemeContext   this.context
不使用context的方式:将使用数据的整个组件作为props传递下去,减少props传递的数量,如果传递多个组件下去,使用多个属性进行传递,类似于slots的东西。

<ThemeContext.consumer>{ value => xx }</ThemeContext.consumer>

使用displayName设置在devTool中显示的名字

* 使用多个context的情况
<ThemeContext1.consumer>{ value1 => (
	<ThemeContext2.consumer>{ value2 =>//使用值的地方
    ) }</ThemeContext2.consumer>
) }</ThemeContext1.consumer>


错误边界组件

避免部分ui的js错误导致整个应用的崩溃

捕获构造 渲染 生命周期期间发生的错误,使用备用的组件

	1.捕获错误信息
    componentDidCatch(error) {
    	//
    }
    2.渲染错诶的组件
    static gerDerivedStateFromError() {
    	return {} //更新state
    }

使用ref转发

	1.创建ref
    const ref = React.createRef()
    2.自定义组件
    const Xxx = React.forwardRef((props,ref) => (
    	<div ref={ref}></div>
        { props.children }
    ))
    3.获取ref指向的dom元素
    ref.current

高阶组建中转发ref

	属性可以层层透传下去
    ref或者key不会传下去
    使用forwardRef传到指定的组件

使用Fragment

	<React.Fragment>
    	//可以不用有父标签
    </React.Fragment>
    or
    <></>
    
    循环使用时传递key

高阶组件(HOC)

参数是组件,返回值是组件的函数

	使用组合的方式,避免直接修改传入的组件的原型
    类似于容器的组件模式
    
    function xx(WrapperComponent) {
    	return class extends React.Component {
        	conponentDidMount() {
            	
            }
            render() {
            	return (
                	<WrapperComponent {...this.props}>
                    	
                    </WrapperComponent>
                )
            }
        }
    }
    
    //将原组件的静态方法拷贝到新的组件上面
    

与第三方库一起使用

	React一般自己维护dom的更新,如果第三方更新相同的dom,会出现问题。
    通过禁止组件的更新来避免冲突
    

深入jsx的高级用法

	<Xxx.Xx>
    <xx[xx]>
    使用展开运算符赋值整个props
    { ...this.props }
    设置只传递部分属性
    { xx,...other } = props
    
    开始和结束标签之间的jsx内容可以通过props.children传递给外层的组件
    
    {}用于js表达式
    
    { true && <Xxx/> }
    

性能优化

减少dom的操作

部署时使用生产版本

	shouldComponentUpdate
    当props或者state发生变化时,比较虚拟dom的变化
    diff算法
    
    使用React.PureComponent 实现对属性和状态的浅比较 代替去自行处理shouldComponentUpdate
    
    改变数据时不改变原数据
    this.setState(state => (
    	{
        	xx: state.xx.concat(['xx'])
        }
    ))
    
    Object.assign({},xx,{xx:xx})
    

portal

将子节点渲染到父组件之外的节点中

		React.createPortal(child,container)

Profiler

可以用于测量渲染的频率和渲染使用的时间 开销

识别渲染比较慢的部分

<Profiler id="xxx" onRender={callback}> </Profiler>

创建React组件的几种方式

	1. function Xxx(props) {
    	return (
        	//
        )
    }
    
    2.class Xxx extends React.Component {
    	constructor(props) {
        	super(props)
            this.state = {
            	xx:xx
            }
            //es6的方法需要绑定this
            this.xx = this.xx.bind(this)
        }
        render() {
        	return (
            	xxx
            )
        }
    }
    
    //前两种实现方式设置默认props的方式
    Xxx.defaultProps = {
    	xx:xx
    }
    
    3.不使用es6的方式
    
    安装create-react-class插件
    createReactClass({
    	render: function() {
        	return xxx
        }
        //设置默认属性的方式
        getDefaultProps: function() {
        	return {
            	xx:xx
            }
        }
        
       //初始化state
       getInitialState: function() {
       		return {
            	xx:xx
            }
       }
       
       //方法会自动绑定到this中不需要绑定
       
    })

使用mixins

	相同的功能,生命周期方法
    mixins: [xx] //常用的设置定时器和清除定时器
    

diffing算法

复杂度 O(n^3)

	1.根节点类型不同,拆卸原树,重新建树
    2.元素相同时候,比较元素的属性,更新改变的属性
    3.子组件节点
    4.子节点进行递归
    

refs和dom

	1.焦点 文本选择
    2.触发强制动画
    3.使用第三方的dom库
    
    在html元素 class组件上使用ref,函数组件不能使用ref
    
    
    回调ref
    ref={el => this.xx = el}
    

渲染属性 render props

	<Xxx render={data => (
    //返回自定义的渲染函数
    // 不渲染自身
    //告知组件需要渲染的内容
    
    )}></Xxx>
    
    组件中部分内容的渲染使用回调函数
    { this.props.render(this.state) }
    
    children={ data => (
      //
    ) }

静态类型检查

	编译时检测错误或者bug信息
	flow typescript
    
    
    1.安装 npx create-react-app xx --template typescript
    2.配置
    	sctript: {
        	"buid":"tsc"
        }
    3.npx tsc --init 生成tsconfig.json文件
    
    {
    	"compilerOptions": {
        	"rootDir": xx,
            "outDir": xxx
        }
    }
    
    4.编译器依赖于声明文件
    类型声明
    declarations.d.ts
    
    

严格模式

<React.StrictMode>
	//开启严格模式
</React.StrictMode>

1.识别不安全的声明周期方法
2.过时的api
3.错误的findDom方法


react的工作过程:
1.提交 componentDidMount componentDidUpdate;
2.渲染
//使用concurrent模式将渲染拆解成多个部分,实现不阻塞的渲染

react内置的类型检查 propType

	声明组件的propsType,
    Xxx.propType = {
    	"xx":PropType.array | bool | object | number | element.isRequired
    }
    设置默认的属性
    XXx.defaultProps = {
    	xx:xx
    }

使用非受控组件

一般表单提交是使用受控组件,也就是将控制权交给react组件,

非受控组件是将控制权交给dom节点


webComponent

react组件是声明式解决方案 ,用户可以自定义一些组件使用

webComponent组件是一些内嵌的组件,这种组件可以像使用标签一样去使用


	1.react组件中使用webComponent
    
    render() {
    	retutn (
        	<x-search class="xx">
            	
            </x-search>
        )
    }
    
    2.webComponent组件中使用react组件
    
    class Xxx extends HTMLElement {
    	connectedCallback() {
        	//创建dom
            //将创建的reactDom放到dom中
            ReactDom.render()
        }
    }
    

核心api讲解


	1.顶层对象React 入口
    2.ReactDOMServer 将组件渲染成静态标记

hook特性

函数组件没有state也可以实现类似于state的功能


	import { useState } from 'react' //钩子 钩住state或者生命周期的函数
    const [xx,setXxx] = useState(0);//通过以上的方式初始化使用的状态值以及改变状态值的方法
    
    //类似于state的使用 但是数据格式更加的灵活
    
    

EffectHook

增加额外能力 组件挂载 更新

	import { useEffect } from 'react';
    
    useEffect(() => {
    	//类似于componentDidMount componentDidUpdate 
        //初次和每次渲染后调用一次 使用props state
    })
    
    hook使用规则:
    1.最外层函数使用
    2.react的函数组件中使用
    

自定义hook