当前位置 : 主页 > 网页制作 > React >

二、React组件化

来源:互联网 收集:自由互联 发布时间:2021-06-15
使用第三方组件 安装: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

使用第三方组件

安装: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 形式,而且要注意是浅比较

网友评论