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>
);
});