二、React组件化

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.js

const { 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

回到顶部