hb

React一些不常用知识

Snipaste_20200519_011057.jpg

react使用lazy()和Suspense实现根据路由进行代码分割

作用:可以加快首页加载时间

        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom'; import React, { Suspense, lazy } from 'react'; const Home = lazy(() => import('./home')); const Bar = lazy(() => import('./bar')); const App = () => ( <Router> <Suspense fallback={<div>loading</div>}> <div> <ul> <li><Link to="/">Home></Link></li> <li><Link to="/bar">Bar></Link></li> </ul> </div> <Switch> <Route exact path="/" component={Home} /> <Route path="/bar" component={Bar} /> </Switch> </Suspense> </Router> ) export default App;
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
import React, { Component } from 'react'; class Home extends Component { render() { return ( <div> Home </div> ); } } export default Home;
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
import React, { Component } from 'react'; class Bar extends Component { render() { return ( <div> bar </div> ); } } export default Bar

20181205103320491.gif

参考博客

错误边界(开发环境下依旧会报错)

        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { error: null, errorInfo: null }; } componentDidCatch(error, errorInfo) { // Catch errors in any components below and re-render with error message this.setState({ error: error, errorInfo: errorInfo }) // You can also log error messages to an error reporting service here } render() { if (this.state.errorInfo) { // Error path return ( <div> <h2>出错了</h2> <details> {this.state.error && this.state.error.toString()} <br /> {this.state.errorInfo.componentStack} </details> </div> ); } // Normally, just render children return this.props.children; } } class BuggyCounter extends React.Component { constructor(props) { super(props); this.state = { counter: 0 }; this.handleClick = this.handleClick.bind(this); } handleClick() { this.setState(({ counter }) => ({ counter: counter + 1 })); } render() { if (this.state.counter === 5) { // Simulate a JS error throw new Error('I crashed!'); } return <h1>{this.state.counter}</h1>; } } function App() { return ( <div> <p> <b> 错误边界示例 <br /><br /> 单击数字以增加计数器。 <br /> 当计数器达到5时,程序会自动抛出。这将模拟组件中的JavaScript错误。 </b> </p> <hr /> <ErrorBoundary> <p>这两个计数器位于同一个错误边界内。如果一个崩溃,错误边界将同时替换它们。</p> <BuggyCounter /> <BuggyCounter /> </ErrorBoundary> <hr /> <p>这两个计数器都在各自的错误边界内。因此,如果一个崩溃,另一个不会受到影响。</p> <ErrorBoundary><BuggyCounter /></ErrorBoundary> <ErrorBoundary><BuggyCounter /></ErrorBoundary> </div> ); } export default App;

Fragments

相当于Vue的 template 可以无需添加多余的

Portals

Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案。 下面是典型应用对话框

App.css

        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
#modal-root { position: relative; z-index: 999; } .app { height: 10em; width: 10em; background: lightblue; overflow: hidden; } .modal { background-color: rgba(0,0,0,0.5); position: fixed; height: 100%; width: 100%; top: 0; left: 0; display: flex; align-items: center; justify-content: center; }
        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
import React from 'react'; import ReactDOM from 'react-dom'; import "./App.css" // These two containers are siblings in the DOM const modalRoot = document.getElementById('modal-root'); // Let's create a Modal component that is an abstraction around // the portal API. class Modal extends React.Component { constructor(props) { super(props); // Create a div that we'll render the modal into. Because each // Modal component has its own element, we can render multiple // modal components into the modal container. this.el = document.createElement('div'); } componentDidMount() { // Append the element into the DOM on mount. We'll render // into the modal container element (see the HTML tab). modalRoot.appendChild(this.el); } componentWillUnmount() { // Remove the element from the DOM when we unmount modalRoot.removeChild(this.el); } render() { // Use a portal to render the children into the element return ReactDOM.createPortal( // Any valid React child: JSX, strings, arrays, etc. this.props.children, // A DOM element this.el, ); } } // The Modal component is a normal React component, so we can // render it wherever we like without needing to know that it's // implemented with portals. class App extends React.Component { constructor(props) { super(props); this.state = {showModal: false}; this.handleShow = this.handleShow.bind(this); this.handleHide = this.handleHide.bind(this); } handleShow() { this.setState({showModal: true}); } handleHide() { this.setState({showModal: false}); } render() { // Show a Modal on click. // (In a real app, don't forget to use ARIA attributes // for accessibility!) const modal = this.state.showModal ? ( <Modal> <div className="modal"> <div> With a portal, we can render content into a different part of the DOM, as if it were any other React child. </div> This is being rendered inside the #modal-container div. <button onClick={this.handleHide}>Hide modal</button> </div> </Modal> ) : null; return ( <div className="app"> This div has overflow: hidden. <button onClick={this.handleShow}>Show modal</button> {modal} </div> ); } } export default App

Render Props

这是官方给的一个例子,让一张图片跟随鼠标

        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
import img1 from "./cat.jpg" class Cat extends React.Component { render() { const mouse = this.props.mouse; return ( <img src={img1} style={{ position: 'absolute', left: mouse.x, top: mouse.y }} alt=""/> ); } } class Mouse extends React.Component { constructor(props) { super(props); this.handleMouseMove = this.handleMouseMove.bind(this); this.state = { x: 0, y: 0 }; } handleMouseMove(event) { this.setState({ x: event.clientX, y: event.clientY }); } render() { return ( <div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}> {/* Instead of providing a static representation of what <Mouse> renders, use the `render` prop to dynamically determine what to render. */} {this.props.render(this.state)} </div> ); } } class MouseTracker extends React.Component { render() { return ( <div> <h1>移动鼠标!</h1> <Mouse render={mouse => ( <Cat mouse={mouse} /> )}/> </div> ); } } export default MouseTracker

解释一下官方的这个例子

  1. 给Mouse组件传一个属性render(也可以叫其他名字),属性是一个高级组件{function(mouse) {return < Cat mouse={mouse} />}
  2. Mouse用这个函数{this.props.render(this.state)}渲染出这个高阶组件

forceUpdate()

可以用this.forceUpdate()强制渲染 调用 forceUpdate() 将致使组件调用 render() 方法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发正常的生命周期方法,包括 shouldComponentUpdate() 方法。如果标记发生变化,React 仍将只更新 DOM。

defaultProps

defaultProps 可以为 Class 组件添加默认 props。这一般用于 props 未赋值,但又不能为 null 的情况

React.PureComponent

React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层比较。如果对象中包含复杂的数据结构,则有可能因为无法检查深层的差别,产生错误的比对结果

此外,React.PureComponent 中的 shouldComponentUpdate() 将跳过所有子组件树的 prop 更新。因此,请确保所有子组件也都是“纯”的组件。

下面是一段代码,父组件的渲染并不会影响到子组件

        
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
class Parent extends React.Component { constructor(props) { console.log("constructor") super(props) this.state = { count: 0 } } add = () => { this.setState((state) => { return { count: state.count + 1 }; }) } render() { console.log('父组件渲染') return ( <div > <div > count:{this.state.count} <button onClick={this.add}>子组件count+1</button> </div> <Son> </Son> </div> ); } } class Son extends React.PureComponent { constructor(props) { console.log("constructor") super(props) this.state = { count: 0 } } render() { console.log('子组件渲染') return ( <div > <div > 子组件 </div> </div> ); } } export default Parent

此文大部分参考 官网文档

———end———

Article at   2020/05/18 17:12  Published  code  Category,viewed  217  times

Relevant tags:    React 

Address:   https://www.kedong.me/article/12

Copyright Notice: Freely reproduced for non-commercial use