React高级

目录

异步加载组件

Context

错误边界

Refs and the DOM

Fragments

高阶组件

使用 Fetch

  高阶组件应用

严格模式

使用 PropTypes 进行类型检查

Optimizing


异步加载组件

React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)。

使用之前:

import OtherComponent from './OtherComponent';

使用之后:

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

 看具体代码:

                                    LazyMain.jsx
import React, { Component, Suspense } from 'react'
// import Other from './Other'
const Other = React.lazy(() => import('./Other'))
/**
 * fallback: 属性接受任何在组件加载过程中的你要展示的内容(React元素)
 * 可以将 Suspense 组件置于懒加载组件之上的任何位置。甚至可以用一个 Suspense 组件包裹多个懒加载组件。
 */
export default class LazyMain extends Component {
    render() {
        return (
            
loading...
}>
) } } Other.jsx import React, { Component } from 'react' export default class Other extends Component { render() { return (

异步加载组件

) } }

Context

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

我们先看看正常三个组件传递参数是怎样的:

                                        Theme1Main.jsx
import React, { Component } from 'react'
import ToolBar from './ToolBar'
export default class Theme1Main extends Component {
    constructor(props){
        super(props)
        this.state ={
            msg:"Theme1Main_msg_data"
        }
    }
    render() {
        return (
            
) } } ToolBar.jsx import React, { Component } from 'react' import LastChild from './LastChild' export default class ToolBar extends Component { render() { return (
) } } LastChild.jsx import React, { Component } from 'react' export default class LastChild extends Component { render() { return (

LastChild

{this.props.msg}

) } }

 使用 context, 我们可以避免通过中间元素传递 props:

                                        Theme2Main.jsx
import React, { Component } from 'react'
import Toolbar from './Toolbar'
/**
 * Provider:提供者
 * Consumer:接受者
 * React.createContext("默认数据"):创建Context
 * 尽可能避免使用,组件的复用性变得很差
 */
export const { Provider, Consumer } = React.createContext('default_data')
export default class Theme2Main extends Component {
    render() {
        return (
            
) } } Toolbar.jsx import React, { Component } from 'react' import LastChild from './LastChild' export default class Toolbar extends Component { render() { return (
) } } LastChild.jsx import React, { Component } from 'react' import { Consumer } from './Theme2Main' export default class LastChild extends Component { render() { return (

LastChild

{ value => { return

{value}

} }
) } }

错误边界

错误边界是一种 React 组件,这种组件可以捕获发生在其子组件树任何位置的 JavaScript 错误,并打印这些错误,同时展示降级 UI,而并不会渲染那些发生崩溃的子组件树。

如果一个 class 组件中定义了 static getDerivedStateFromError() 或 componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。

                                       ErrorMain.jsx     
import React, { Component } from 'react'
import ErrorBoundary from './ErrorBoundary'
import List from './List'
export default class ErrorMain extends Component {
    render() {
        return (
            
                
            
        )
    }
}
                                        ErrorBoundary.jsx
import React, { Component } from 'react'

export default class ErrorBoundary extends Component {
    constructor(props) {
        super(props)
        this.state = {
            hasError: false
        }
    }
    static getDerivedStateFromError(error) {
        // 更新State 使下一次渲染能够显示降级后的UI
        return {
            hasError: true
        }
    }
    componentDidCatch(error, errorInfo) {
        // 发送错误,将错误信息发送给后台
        console.log(error, errorInfo)
    }
    render() {
        if (this.state.hasError) {
            // 发生错误:降级显示新的UI
            return 

发生了错误!!!

} // 组件组合 return this.props.children } } List.jsx import React, { Component } from 'react' export default class List extends Component { constructor(props) { super(props) this.state = { list: ['tom', 'jack'] } } render() { return (
    { this.state.list.map((ele, index) => { return
  • {ele}
  • }) }
) } }

 注意:错误边界仅可以捕获其子组件的错误,它无法捕获其自身的错误。如果一个错误边界无法渲染错误信息,则错误会冒泡至最近的上层错误边界,这也类似于 JavaScript 中 catch {} 的工作机制。

Refs and the DOM

Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。

Refs 是使用 React.createRef() 创建的,并通过 ref 属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。

当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问

不能在函数组件上使用 ref 属性,因为他们没有实例

                                        RefsMain.jsx
import React, { Component } from 'react'

export default class RefsMain extends Component {
    constructor(props){
        super(props)
        this.text = React.createRef()
    }
    componentDidMount(){
        //Dom渲染完成
        this.text.current.innerHTML = 'change after data'
    }
    render() {
        return (
            

文本信息

) } }

Fragments

React 中的一个常见模式是一个组件返回多个元素。Fragments 允许你将子列表分组,而无需向 DOM 添加额外节点。

                                       FragmentMain.jsx
import React, { Component } from 'react'
/**
 * React.Fragment:实现容器功能,单不会渲染成节点
 */
export default class FragmentMain extends Component {

    constructor() {
        super();
        this.state = {
            hasFlag: true
        }
    }
    render() {
        return (
            

Fragment

{ this.state.hasFlag ?

内容1

内容2

内容3

内容4

: // 简写 <>

内容5

内容6

内容7

内容8

}
) } }

高阶组件

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

具体而言,高阶组件是参数为组件,返回值为新组件的函数。高阶组件是将组件转换为另一个组件

                                        HigherMain.jsx
import React, { Component } from 'react'
/**
 * 高阶组件
 *     1. 函数
 *     2. 参数是一个组件
 *     3. 返回值也是一个组件
 * 高阶组件的作用:提取可复用的部分,增加可复用性
 */
const withFetch =(ComposeComponent)=>{//ComposeComponent  'C'必须大写
    return class extends React.Component{
        componentDidMount(){
            console.log('hello')
        }
        render(){
            return 
        }
    }
}
class MyData extends React.Component{
    render(){
        return (
            
MyData:{this.props.data}
) } } const WithFetch =withFetch(MyData) export default class HigherMain extends Component { render() { return (
) } }

使用 Fetch

fetch('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data));

 这里我们通过网络获取一个 JSON 文件并将其打印到控制台。最简单的用法是只提供一个参数用来指明想 fetch() 到的资源路径,然后返回一个包含响应结果的 promise(一个 Response 对象)。

当然它只是一个 HTTP 响应,而不是真的 JSON。为了获取 JSON 的内容,我们需要使用 json() 方法(该方法返回一个将响应 body 解析成 JSON 的 promise)。

// Example POST method implementation:
async function postData(url = '', data = {}) {
  // Default options are marked with *
  const response = await fetch(url, {
    method: 'POST', // *GET, POST, PUT, DELETE, etc.
    mode: 'cors', // no-cors, *cors, same-origin
    cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
    credentials: 'same-origin', // include, *same-origin, omit
    headers: {
      'Content-Type': 'application/json'
      // 'Content-Type': 'application/x-www-form-urlencoded',
    },
    redirect: 'follow', // manual, *follow, error
    referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
    body: JSON.stringify(data) // body data type must match "Content-Type" header
  });
  return response.json(); // parses JSON response into native JavaScript objects
}

postData('https://example.com/answer', { answer: 42 })
  .then(data => {
    console.log(data); // JSON data parsed by `data.json()` call
  });
                                        News.jsx
import React, { Component } from 'react'

export default class News extends Component {
    constructor(props) {
        super(props);
        this.state = {
            movement: []
        }
    }
    componentDidMount() {
        fetch('http://iwenwiki.com/api/blueberrypai/getIndexMovement.php')
            .then(res => res.json())
            .then(data => {
                console.log(data)
                this.setState({
                    movement: data.movement
                })
            })
    }
    render() {
        return (
            

新闻渲染

    { this.state.movement.map((ele, index) => { return
  • {ele.content}
  • }) }
) } }

  高阶组件应用

                                        Banner.jsx
import React from 'react'
import withFetch from './withFetch'
const Banner = withFetch('http://iwenwiki.com/api/blueberrypai/getIndexMovement.php')(props => {
    return (
        

高阶组件应用

    { props.data.movement.map((ele, index) => { return
  • {ele.content}
  • }) }
) } ) export default Banner withFetch.jsx import React from 'react' const withFetch = (url) => (View) => { return class extends React.Component { constructor(props) { super(props) this.state = { data: null, loadding: true, } } componentDidMount() { fetch(url).then(res => res.json()) .then(data => { this.setState({ loadding: false, data }) }) } render() { if (this.state.loadding) { return (
loading......
) }else{ return } } } } export default withFetch

严格模式

StrictMode 是一个用来突出显示应用程序中潜在问题的工具。与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。
     1. 识别不安全的生命周期
     2. 关于使用过时字符串 ref API 的警告
     3. 关于使用废弃的 findDOMNode 方法的警告
     4. 检测意外的副作用
     5. 检测过时的 context API
 StrictMode严格模式只有在开发环境下生效,在生产模式下无效

 

                                       StrictModeMain.jsx
import React, { Component } from 'react'
import ErrorAble from './ErrorAble'
export default class StrictModeMain extends Component {
    render() {
        return (
            

严格模式

) } } ErrorAble.jsx import React, { Component } from 'react' export default class ErrorAble extends Component { /** * 过时的 */ componentWillMount() { console.log("DOM渲染之前"); } componentDidMount() { console.log("DOM渲染之后"); } render() { return (

测试严格模式

) } }

使用 PropTypes 进行类型检查

随着应用程序不断增长,可以通过类型检查捕获大量错误。PropTypes 提供一系列验证器,可用于确保组件接收到的数据类型是有效的

当传入的 prop 值类型不正确时,JavaScript 控制台将会显示警告。出于性能方面的考虑,propTypes 仅在开发模式下进行检查。

propTypes 类型检查发生在 defaultProps 赋值后,所以类型检查也适用于 defaultProps

                                    PropMain.jsx
import React, { Component } from 'react'
import Greeting from './Greeting'
export default class PropMain extends Component {
    render() {
        return (
            

Props类型验证

) } } Greeting.jsx import React, { Component } from 'react' import PropTypes from 'prop-types' export default class Greeting extends Component { render() { return (

{this.props.title}

{this.props.age}

) } } // 类型验证 Greeting.propTypes = { title:PropTypes.string, age:PropTypes.number } // 默认值 Greeting.defaultProps ={ age:0 } // typeScript:js高集,增加了静态类型检查 // Flow

Optimizing

                                    OptimizingMain.jsx
import React, { Component } from 'react'
import Child1 from './Child1'
import Child2 from './Child2'
export default class OptimizingMain extends Component {
    constructor(props) {
        super(props);
        this.state = {
            message: "消息提示",
            count: 0
        }
    }
    incrementHandle = () => {
        this.setState({
            count: this.state.count + 1
        })
    }
    render() {
        console.log("主文件 ---> render");
        return (
            

性能优化

{this.state.count}

) } } Child1.jsx import React, { Component } from 'react' export default class Child1 extends Component { render() { console.log("child1 ---> render"); return (

Child1

{ this.props.message }

) } } Child2.jsx import React, { Component } from 'react' export default class Child2 extends Component { render() { console.log("Child2 ---> render"); return (

Child2

{this.props.message}

) } }

React高级_第1张图片

 从上面的代码和视图可以看到,只要父组件加载或更新了,其子组件也会加载,那如何优化呢?

1.PureComponent
         PureComponent:对数据进行浅比较
         Component:不会对数据进行比较

2.shouldComponentUpdate

                                Child2.jsx
import React, { Component } from 'react'

export default class Child2 extends React.PureComponent {
    render() {
        console.log("Child2 ---> render");
        return (
            

Child2

{this.props.message}

) } }
                                   Child1.jsx
import React, { Component } from 'react'

export default class Child1 extends Component {

    /**
     * 优化
     */
    shouldComponentUpdate(nextProps,nextState){
        if(nextProps.message === this.props.message){
            return false;
        }
        return true;
    }

    render() {
        console.log("child1 ---> render");
        return (
            

Child1

{ this.props.message }

) } }

 对于组件来说,很多时候,我们需要做性能优化:

    1. 定时器:在组件销毁时,需要取消

    2. 网络请求:在组件销毁时,取消网络请求

    3. 事件监听:在组件销毁时,需要销毁事件处理函数

                                    Optimizing2Math.jsx
import React, { Component } from 'react'
const MyAPI = {
    count: 0,
    subScribe(cb) {
        this.intervarId = setInterval(() => {
            this.count += 1
            cb(this.count)
        }, 1000)
    },
    unSubScribe() {
        clearInterval(this.intervarId);
        this.reset();
    },
    reset() {
        this.count = 0;
    }
}
export default class Optimizing2Math extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }
    componentDidMount() {
        MyAPI.subScribe(currentCount => {
            this.setState({
                count: currentCount
            })
        })
    }
    componentWillUnmount() {
        // 组件销毁之前,先清除定时器
        MyAPI.unSubScribe();
    }
    render() {
        return (
            

性能优化2

{this.state.count}

) } }

React高级先到这里,接下来更新的是网络请求部分的基础知识......

你可能感兴趣的:(JavaScript,react)