二、React组件化
使用第三方组件
安装:npm install antd --save
试用 ant-design 组件库
import React, { Component } from 'react'import Button from 'antd/lib/button';
import 'antd/dist/antd.css'
export default class TestAntd extends Component {
render() {
return (
<div>
<Button type="primary">Button</Button>
</div>
)
}
}
上面 import 的内容太长,不利于日常开发
配置按需加载
安装 react-app-rewired 取代 react-scripts,可以扩展webpack的配置,类似 vue.config.js
npm install react-app-rewired customize-cra babel-plugin-import -D
// 根目录创建 config-overrides.jsconst { override, fixBabelImports, addDecoratorsLegacy } = require("customize-cra")
module.exports = override(
fixBabelImports("import", {
libraryName: "antd",
libraryDirectory: "es",
style: "css"
}),
addDecoratorsLegacy() // 配置装饰器,这里如果配置,需要先安装下面的npm
)
修改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
例如:高级组件链式调用
import React, { Component } from 'react'const foo = Cmp => props => {
return <div style={{border: '1px solid red'}}>
<Cmp {...props}/>
</div>
}
const foo2 = Cmp => props => {
return <div style={{border: '1px solid green', padding: '10px'}}>
<Cmp {...props}/>
</div>
}
function Child(props){
return <div>Child</div>
}
export default class HocPage extends Component {
render() {
const Foo = foo2(foo(Child))
return (
<div>
<h1>HocPage</h1>
<Foo />
</div>
)
}
}
改为装饰器的写法:装饰器只能用于装饰 class 组件
import React, { Component } from 'react'const foo = Cmp => props => {
return <div style={{border: '1px solid red'}}>
<Cmp {...props}/>
</div>
}
const foo2 = Cmp => props => {
return <div style={{border: '1px solid green', padding: '10px'}}>
<Cmp {...props}/>
</div>
}
@foo2
@foo
class Child extends Component {
render(){
return <div>Child</div>
}
}
export default class HocPage extends Component {
render() {
return (
<div>
<h1>HocPage</h1>
<Child />
</div>
)
}
}
注意:需要引入 antd样式文件: import 'antd/dist/antd.css';
使用antd的Form表单
import React, { Component } from 'react'import {Form, Input, Icon, Button} from 'antd'
const FormItem = Form.Item
export default class FormPage extends Component {
constructor(props){
super(props)
this.state = {
name: '',
password: ''
}
}
change = (field, event)=>{
this.setState({
[field]: event.target.value
})
}
submit = ()=>{
console.log('state', this.state);
}
render() {
return (
<div>
<h1>FormPage</h1>
<Form>
<FormItem label="姓名">
<Input prefix={<Icon type="user"/>} onChange={event => this.change('name', event)}/>
</FormItem>
<FormItem label="密码">
<Input type="password" prefix={<Icon type="lock"/>} onChange={event => this.change('password', event)}/>
</FormItem>
<FormItem>
<Button type="primary" onClick={this.submit}>提交</Button>
</FormItem>
</Form>
</div>
)
}
}
Form中内容的使用 --- Form.create()
import React, {Component} from 'react'import {Form, Input, Icon, Button} from 'antd'
const FormItem = Form.Item
class FormPageDecorators extends Component {
submit = () => {
const { getFieldsValue, getFieldValue } = this.props.form
// 获取所有Field的值
console.log('submit', getFieldsValue());
// 获取单个值
console.log('submitName', getFieldValue('name'));
}
render() {
// 装饰器
const {getFieldDecorator} = this.props.form
console.log(this.props.form);
return (
<div>
<h1>FormPageDecorators</h1>
<Form>
<FormItem label="姓名">
{ getFieldDecorator('name')(<Input prefix={< Icon type = "user" />}/> )}
</FormItem>
<FormItem label="密码">
{ getFieldDecorator('password')(<Input type="password" prefix={< Icon type = "lock" />}/> )}
</FormItem>
<FormItem>
<Button type="primary" onClick={this.submit}>提交</Button>
</FormItem>
</Form>
</div>
)
}
}
export default Form.create()(FormPageDecorators)
表单验证
// 校验规则const nameRule = {
required: true,
message: 'please input your name'
}
const passwordRule = {
required: true,
message: 'please input your password'
}
class FormPageDecorators extends Component {
submit = () => {
const { validateFields } = this.props.form
// 表单验证
validateFields((err, values)=>{
if(err){
console.log('err:', err)
}else{
console.log('submit:', values);
}
})
}
}
<FormItem label="姓名">
{ getFieldDecorator('name', {rules: [nameRule]})(<Input prefix={< Icon type = "user" />}/> )}
</FormItem>
<FormItem label="密码">
{ getFieldDecorator('password', {rules: [passwordRule]})(<Input type="password" prefix={< Icon type = "lock" />}/> )}
</FormItem>
自己写一个Form.create()
import React, { Component } from 'react'function kFormCreate(Cmp){
return class extends Component {
constructor(props){
super(props)
this.options = {} // 配置字段项
this.state = {} // 存字段值
}
handleChange = (event)=>{
const {name, value} = event.target
this.setState({
[name]: value
})
}
getFieldDecorator = (field, options)=>{
this.options[field] = options
return InputCmp=>(
<div className="border">
{React.cloneElement(InputCmp,{
name: field,
value: this.state[field] || "",
onChange: this.handleChange
})}
</div>
)
}
getFieldsValue = ()=>{
return {...this.state}
}
getFieldValue = (field)=>{
return this.state[field]
}
validateFields = (callback)=>{
const tem = {...this.state}
const err = []
for(let i in this.options){
if(tem[i] === undefined){
err.push({
[i]: 'error'
})
}
}
if(err.length>0){
callback(err, tem)
}else{
callback(undefined, tem)
}
}
render(){
return (
<div className="border">
<Cmp {...this.props}
getFieldDecorator={this.getFieldDecorator}
getFieldsValue={this.getFieldsValue}
getFieldValue={this.getFieldValue}
validateFields={this.validateFields}
/>
</div>
)
}
}
}
// 校验规则
const nameRule = {
required: true,
message: 'please input your name'
}
const passwordRule = {
required: true,
message: 'please input your password'
}
class MyFormPage extends Component {
submit = ()=>{
const {getFieldsValue, getFieldValue, validateFields} = this.props
validateFields((err, values)=>{
if(err){
console.log('err', err);
}else{
console.log('submitSuccess:',values);
}
})
}
render() {
const {getFieldDecorator} = this.props
return (
<div>
<h1>MyFormPage</h1>
{
getFieldDecorator('name',{rules: [nameRule]})(
<input type="text"/>
)
}
{
getFieldDecorator('password',{rules: [passwordRule]})(
<input type="password"/>
)
}
<button onClick={this.submit}>提交</button>
</div>
)
}
}
export default kFormCreate(MyFormPage)
Dialog组件(弹窗组件)
Dialog.js
import React, { Component } from 'react'import {createPortal} from 'react-dom';
export default class Dialog extends Component {
constructor(props){
super(props)
const doc = window.document
this.node = doc.createElement('div')
doc.body.appendChild(this.node)
}
componentWillUnmount(){
window.document.body.removeChild(this.node)
}
render() {
return createPortal(
<div className="dialog">
<h1>Dialog</h1>
</div>,
this.node
)
}
}
DialogPage.js
import React, { Component } from 'react'import {Button} from 'antd';
import Dialog from '../components/Dialog';
export default class DialogPage extends Component {
constructor(props){
super(props)
this.state = {
showDialog: false
}
}
handleShowDialog = ()=>{
this.setState({
showDialog: !this.state.showDialog
})
}
render() {
const {showDialog} = this.state
return (
<div>
<h1>DialogPage</h1>
<Button onClick={this.handleShowDialog}>dialog toggle</Button>
{
showDialog && <Dialog />
}
</div>
)
}
}
树形组件
css文件
.tri {width: 20px;
height: 20px;
margin-right: 2px;
padding-right: 4px;
}
.tri-close:after,
.tri-open:after {
content: "";
display: inline-block;
width: 0;
height: 0;
border-top: 6px solid transparent;
border-left: 8px solid black;
border-bottom: 6px solid transparent;
}
.tri-open:after {
transform: rotate(90deg);
}
TreeNode.js
import React, { Component } from 'react'import classnames from 'classnames';
export default class TreeNode extends Component {
constructor(props){
super(props)
this.state = {
expanded: false
}
}
handleExpanded = ()=>{
this.setState({
expanded: !this.state.expanded
})
}
render() {
const {title, children} = this.props.data
const {expanded} = this.state
const hasChildren = children && children.length > 0
return (
<div>
<div className="nodesInner" onClick={this.handleExpanded}>
{
hasChildren &&
<i className={classnames("tri", expanded ? 'tri-open':'tri-close')}></i>
}
<span>{title}</span>
</div>
{
hasChildren && expanded &&
<div className="children">
{
children.map(item=>{
return <TreeNode key={item.key} data={item}/>
})
}
</div>
}
</div>
)
}
}
TreePage.js
import React, { Component } from 'react'import TreeNode from '../components/TreeNode';
//数据源
const treeData = {
key: 0, //标识唯⼀一性
title: "全国", //节点名称显示
children: [ //⼦子节点数组
{
key: 6,
title: "北方区域",
children: [{
key: 1,
title: "⿊龙江省",
children: [{
key: 6,
title: "哈尔滨",
}, ],
}, {
key: 2,
title: "北京",
}, ],
}, {
key: 3,
title: "南方区域",
children: [{
key: 4,
title: "上海",
}, {
key: 5,
title: "深圳",
}, ],
},
],
};
export default class TreePage extends Component {
render() {
return (
<div>
<h1> TreePage </h1>
<TreeNode data={treeData}/>
</div>
)
}
}
常见组件优化技术
定制组件的 shouldComponentUpdate 钩子
import React, { Component } from 'react'export default class CommentList extends Component {
constructor(props){
super(props)
this.state = {
comments: []
}
}
componentDidMount(){
setInterval(() => {
this.setState({
comments: [{
author: "⼩明",
body: "这是小明写的⽂文章",
}, {
author: "小红",
body: "这是小红写的⽂文章",
}]
})
}, 1000);
}
render() {
const {comments} = this.state
return (
<div>
<h1>CommentList</h1>
{
comments.map(item=>{
return <Comment key={item.author} data={item}/>
})
}
</div>
)
}
}
class Comment extends Component{
shouldComponentUpdate(nextProps, nextState){
const {author, body} = nextProps
const {author: nowAuthor, body: nowBody} = nextProps
if(author===nowAuthor && body === nowBody) {
return false
}
}
render(){
const {author, body} = this.props.data
console.log('render');
return <div className="border">
<p>作者: {author}</p>
<p>内容: {body}</p>
</div>
}
}
PureComponent
import React, { Component, PureComponent } from 'react'export default class PureConponentPage extends Component {
constructor(props){
super(props)
this.state = {
counter: 0
}
}
setCounter = ()=>{
this.setState({
counter: 1
})
}
render() {
const {counter} = this.state
return (
<div>
<h1>PureConponentPage</h1>
<button onClick={this.setCounter}>change</button>
<Demo counter={counter}/>
</div>
)
}
}
class Demo extends PureComponent{
render(){
const {counter} = this.props
console.log('render');
return <div>
{counter}
</div>
}
}
缺点是必须要用 class 形式,而且要注意是浅比较
以上是 二、React组件化 的全部内容, 来源链接: utcz.com/z/384093.html