在 react 中组件化是广泛存在的,可是组件化也是分类型的,接下来将介绍容器组件与展现组件,这2者同为组件,却有着不一样的功效,记住下面这段话,有助于帮你理解容器组件与展现组件:css
基本原则:容器组件负责数据获取与处理;展现组件负责根据全局props
展现信息vue
import React, { Component } from "react";
// 容器组件
export default class CommentVs extends Component {
constructor(props) {
super(props);
this.state = {
comments: []
};
}
// 生命周期函数
componentDidMount() {
setTimeout(() => {
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>
);
}
}
// 展现组件
function Comment({ data }) {
return (
<div>
<p>{data.body}</p>
<p> --- {data.author}</p>
</div>
);
}
复制代码
什么是PureComponent
呢,其实就是定制化后的shouldComponentUpdate
的增强Component
(内部实现浅比较)react
import React, { Component, PureComponent } from "react";
// shouldComponentUpdate的增强版
class PureComponentTest extends PureComponent {
constructor(props) {
super(props);
this.state = {
comments: [
{ body: "react is very good", author: "facebook" },
{ body: "vue is very good", author: "youyuxi" }
]
};
}
shouldComponentUpdate(nextProps) {
if (
nextProps.data.body === this.props.data.body &&
nextProps.data.author === this.props.data.author
) {
return false;
}
return true;
}
render() {
console.log("render");
return (
<div>
<p>{this.props.body}</p>
<p>------{this.props.author}</p>
</div>
);
}
}
export default PureComponentTest;
复制代码
React.PureComponent的实现原理: webpack
所谓的浅比较,指的就是这行代码!is(objA[keysA[i]], objB[keysA[i]])。能够看到,在比较两个对象中属性的属性值的时候,是直接采用Object.is的方式进行的比较,若是对应属性值刚好是基本类型值固然没有问题,可是若是,刚好对象中的该属性的属性值是引用类型的值,那么比较的仍旧是引用,而不是对象的外形。因而可能出现这种状况,当ObjA和objB的对象外形一致,按道理说不须要更新,可是因为其中某个相同属性的属性值是引用类型,而他们虽然外形也是一致的,可是引用不一样,那么!is(objA[keysA[i]], objB[keysA[i]])仍旧会返回true,最终致使shallowEqual函数返回false(这样shouldComponentUpdate方法会返回true),从而致使组件出现无心义的更新。web
那么为何这里会采用“浅比较”呢?这其实也是出于对于性能的考量。咱们都知道,在js中,对引用类型外形的比较,其实是须要经过递归比较才能完成(深复制引用类型也须要经过递归完成)。而在组件更新判断的生命周期中不断执行递归操做去比较前后的props和state对象,毫无疑问会产生较大的性能开销。因此这里只能折中,采用浅比较的方式。固然反作用就是,仍可能出现没有必要的从新渲染(也就是两个对象的外形一致,但其中的某些属性是引用类型,这样即便引用类型属性值的外形也是一致的,浅比较依旧断定这两个对象不一样,从而致使多余的从新渲染)。npm
React.memo
是 React v16.6.0 以后的版本,可使用 React.memo
让函数式的组件也有PureComponent
的功能json
const Joke = React.memo(() => (
<div>
{/* ||若是value为空,则显示 loding*/}
{this.props.value || 'loading...' }
</div>
));
复制代码
首先给对应项目工程安装依赖,执行命令 npm install antd --save
bash
简单示例,button按钮的使用服务器
import React, { Component } from 'react'
// 导入antd 按钮组件
import Button from 'antd/lib/button'
// 导入antd 样式表
import "antd/dist/antd.css"
class ButtonTest extends Component {
render() {
return (<div className="App">
{/*使用antd button 组件*/}
<Button type="primary">Button</Button>
</div>
)
}
}
export default ButtonTest
复制代码
更多内容请参考ant design官方指南 babel
你能够理解为是懒加载,就是在须要的时候才加载组件插件。配置步骤以下:
npm install react-app-rewired@2.1.5 babel-plugin-import --save
npm install customize-cra less less-loader --save
复制代码
const { override,
fixBabelImports,addBabelPlugins
} = require("customize-cra");
module.exports = override(
// antd按需加载
fixBabelImports(
"import", { libraryName: "antd", libraryDirectory: "es", style: "css" }
),
addBabelPlugins(
['@babel/plugin-proposal-decorators', { legacy: true }],
)
);
复制代码
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
},
复制代码
同窗们能够本身对着项目修改调试。
在React
里已经有了HOC(Higher-Order Components)
的概念,也就是高阶组件,高阶组件实际上是返回另一个组件,产生的新的组件能够对属性进行包装,甚至重写部分生命周期。看个例子
const jpsite = (Component) => {
const NewComponent = (props) => {
return <Component {...props} name="开课吧高阶组件" />;
};
return NewComponent;
};
复制代码
上面 jpsite 组件,其实就是代理了一个Component
,只是给原 Component
多传递了一个name参数
import React, { Component } from 'react'
import {Button} from 'antd'
const withName = (Component) => {
const NewComponent = (props) => {
return <Component {...props} name="开课吧高阶组件" />;
};
return NewComponent;
};
const withLog = Component=>{
class NewComponent extends React.Component{
render(){
return <Component {...this.props} />;
}
componentDidMount(){
console.log('didMount',this.props)
}
}
return NewComponent
}
class App extends Component {
render() {
return (
<div className="App">
<h2>hi,{this.props.name}</h2>
<Button type="primary">Button</Button>
</div>
)
}
}
export default withName(withLog(App))
复制代码
withName(withLog(App))
就是链式调用的方式
ES6装饰器可用于简化高阶组件写法,首先安装插件
npm install --save-dev @babel/plugin-proposal-decorators
而后config-overrides.js添加以下内容
import React, { Component } from "react";
// 高阶组件
const withName = Comp => {
// 甚至能够重写组件声明周期
class NewComponent extends Component {
componentDidMount() {
console.log("do something");
}
render() {
return <Comp {...this.props} name="高阶组件试用介绍" />;
}
}
// 假设经过某种特殊手段获取了本节课名字
return NewComponent;
};
const withLog = Comp => {
console.log(Comp.name + "渲染了");
return props => <Comp {...props} />;
};
@withLog
@withName
@withLog
class Jpsite extends Component {
render() {
return (
<div>
{this.props.stage} - {this.props.name}
</div>
);
}
}
export default Jpsite;
复制代码
@withName @withLog三者连在一块儿的写法就是装饰器写法了,效果等同于withName(withLog(App))
这种链式调用的方式
组件跨层级通讯可以使用Context 这种模式下的两个角色,Provider
和Consumer
Provider
为外层组件,用来提供数据;内部须要数据时用Consumer
来读取
import React, { Component } from "react";
// 1. 建立上下文
const Context = React.createContext();
const store = {
// 指定6611尾号用户中奖
name: "恭喜你中到了一等奖",
sayHi() {
console.log(this.name);
}
};
const withProvider = Comp => props => (
<Context.Provider value={store}>
<Comp {...props} />
</Context.Provider>
);
const withConsumer = Comp => props => (
<Context.Consumer>
{/* 必须内嵌一个函数 */}
{value => <Comp {...props} value={value} />}
</Context.Consumer>
);
@withConsumer
class Inner extends Component {
render() {
console.log('Inner');
return <div>{this.props.value.name}</div>;
}
}
@withProvider
class ContextSample extends Component {
render() {
console.log('ContextSample');
return <div><Inner></Inner></div>;
}
}
export default ContextSample
复制代码
写做不易,若是文章对你有帮助,能否留下脚印留个赞~