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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom