React(随笔一)

2019-11-04  本文已影响0人  怪怪牛
扩展webpack配置
// react-app-rewired取代react-scripts
npm install react-app-rewired customize-cra babel-plugin-import -D
解决babel-plugin-import antd import引入问题
//根目录创建config-overrrides.js 
const { override, fixBabelImports } = require("customize-cra");
module.exports = override(
 fixBabelImports("import", {
  libraryName: "antd",
  libraryDirectory: "es",
  style: "css"
  })
);
//修改package.json
"scripts": {
  "start": "react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "react-app-rewired test",
  "eject": "react-app-rewired eject"
},

支持装饰器配置: npm install -D @babel/plugin-proposal-decorators

//config-overrrides.js 
const { addDecoratorsLegacy } = require("customize-cra");
module.exports = override(
 ...,
 addDecoratorsLegacy()
);

解决类容A处声明,却在B处展示

// 常见用法如下:Dialog在当前组件声明,但是却在body中另一个div中显示
<div class="foo">
 <div> ... </div>
{ needDialog ?
  <Dialog>
   <header>Any Header</header>
   <section>Any content</section>
  </Dialog>
 : null }
</div>

方法1:Portal

react v16之后出现的portal可以实现内容传送功能

import React from 'react';
import {createPortal} from 'react-dom';
export default class Dialog extends React.Component {
 constructor(props) {
  super(props);
  const doc = window.document;
  this.node = doc.createElement('div');
  doc.body.appendChild(this.node);
}
 render() {
  return createPortal(
   <div className="dialog">
   {this.props.children}
   </div>, //塞进传送门的JSX
   this.node //传送门的另一端DOM node
 );
}
 componentWillUnmount() {
  window.document.body.removeChild(this.node);
}
}

方案2:unstable_renderSubtreeIntoContainer

在v16之前,要用到react中两个秘而不宣的React API: unstable_renderSubtreeIntoContainer,
unmountComponentAtNode

export class Dialog2 extends React.Component {
 render() {
  return null;
}
 componentDidMount() {
  const doc = window.document;
  this.node = doc.createElement("div");
  doc.body.appendChild(this.node);
  this.createPortal(this.props);
}
 componentDidUpdate() {
  this.createPortal(this.props);
}
 componentWillUnmount() {
  unmountComponentAtNode(this.node);
  window.document.body.removeChild(this.node);
}
 createPortal(props) {
  unstable_renderSubtreeIntoContainer(
   this, //当前组件
   <div className="dialog">{props.children}</div>, // 塞进传送门的JSX
   this.node // 传送门另一端的DOM node
 );
}
}

树形组件设计与实现

import React, { Component } from "react";
class TreeNode extends Component {
 constructor(props) {
  super(props);
  this.state = {
   open: false
 };
}
 toggle = () => {
  if (this.isFolder) {
   this.setState(nextState => ({ open: !nextState.open }));
 }
};
 get isFolder() {
  return this.props.model.children && this.props.model.children.length;
}
 render() {
  return (
   <ul>
    <li>
     <div onClick={this.toggle}>
     {this.props.model.title}
     {this.isFolder ? (
       <span>[{this.state.open ? "-" : "+"}]</span>
     ) : null}
     </div>
    {this.isFolder ? (
      <ul style={{ display: this.state.open ? "block" : "none" }}>
      {this.props.model.children&&this.props.model.children.map(model => (
        <TreeNode model={model} key={model.title} />
      ))}
      </ul>
    ) : null}
    </li>
   </ul>
 );
}
}
export default class Tree extends Component {
 treeData = {
  title: "Web全栈架构师",
  children: [
  {
    title: "Java架构师"
  },
  {
    title: "JS高级",
    children: [
    {
      title: "ES6"
    },
    {
      title: "动效"
    }
   ]
  },
  {
    title: "Web全栈",
    children: [
    {
      title: "Vue训练营",
      expand: true,
      children: [
      {
        title: "组件化"
      },
      {
        title: "源码"
      },
      {
        title: "docker部署"
      }
     ]
    },
    {
      title: "React",
      children: [
      {
        title: "JSX"
      },
      {
        title: "虚拟DOM"
      }
     ]
    },
    {
      title: "Node"
    }
   ]
  }
 ]
};
 render() {
  return <TreeNode model={this.treeData} />;
}
}

常见组件优化技术

1定制组件的shouldComponentUpdate钩子

import React, { Component } from "react";
// 容器组件
export default class CommentList extends Component {
 constructor(props) {
  super(props);
  this.state = {
   comments: []
 };
}
 componentDidMount() {
  setInterval(() => {
   this.setState({
    comments: [
    { body: "react is very good", author: "facebook" },
    { body: "vue is very good", author: "youyuxi" }
   ]
  });
 }, 1000);
}
 render() {
  return (
   <div>
   {this.state.comments.map((c, i) => (
     <Comment key={i} data={c} />
   ))}
   </div>
 );
}
}
class Comment extends Component {
 render() {
  return (
   <div>
    <p>{this.props.data.body}</p>
    <p> --- {this.props.data.author}</p>
   </div>
 );
}
}
shouldComponentUpdate({ data: { body, author } }) {
  if (body === this.props.data.body && author === this.props.data.author) {
    return false;
 }
  return true;
}

PureComponent 必须class形式,而且只进行了浅比较
定制了shouldComponentUpdate后的Component

class Comp extends React.PureComponent {
 render() {
  // 注意这里直接获取body和author
  return (
   <div>
    <p>{this.props.body}</p>
    <p> --- {this.props.author}</p>
   </div>
 );
}
}

React.memo

React v16.6.0 之后的版本,可以使用一个新功能 React.memo 来完美实现让函数式的组件也有了PureComponent的功能

const Comment = React.memo(function({ body, author }) {
 console.log("render");
 return (
  <div>
   <p>{body}</p>
   <p> --- {author}</p>
  </div>
);
});
上一篇 下一篇

猜你喜欢

热点阅读