zoukankan      html  css  js  c++  java
  • 【组件开发笔记】组件の组织

    1、组件设计基本原则

    单一职责。

    也就是:

    ① 降低组件的复杂度,减少代码量,提升可读性。

    ② 降低与其他组件的耦合度(低耦合),从而降低变更导致的对功能的影响。

    ③ 提高可复用性,功能单一(高内聚),有明确的边界,不访问其他组件的内部细节,接口最小化,单向数据流...。

    2、TIPs

    性能:无状态函数组件 > 有状态函数组件 > class组件;

    减少props传递;

    抽取过多的条件控制流;

    不过度优化;

    3、分类

    【展示组件】-【本质:视图】

    通用的组件:开发时,要以“第三方组件库”的标准考虑其设计,不和任何项目的业务耦合

    项目通用的组件:可多个组件共享,可能与业务有较低耦合程度

    组件特有的组件库:与业务深度耦合,不能与其他组件共享。

    【容器组件】-【本质:逻辑】

    侧重业务处理,通常为高阶组件。

    数据来源:直接请求接口或从外部传入。

    然后展示完整的视图。

    【有状态组件&无状态组件】

    无状态组件完全由外部props控制状态。如果想要优化它的props映射,提升性能,可以使用React.memo避免无用渲染。

    React.memo类似于React.PureComponent,两者的区别为:React.memo是用于函数组件的,React.PureComponent是用于类组件的。

    React.memo的用法为:

    const Component = ()=> {
        return (
            <div>嘎嘎嘎</div>
        )
    }
    const MemodFuncComponent = React.memo(Component)
    

      

    React.PureComponent 的用法为:

    import React from 'react';
    
    class Test extends React.PureComponent {
        constructor(props) {
            super(props);
            this.state = {
                count: 0
            }
        }
        
        componentWillUpdate(nextProps, nextState) {
            console.log('componentWillUpdate')
        }
        
        componentDidUpdate(prevProps, prevState) {
            console.log('componentDidUpdate')
        }
        
        render() {
            return ( 
                <div> 
                { this.state.count } 
                <button onClick = {
                    () => this.setState({ count: 1 })
                }>点击</button> 
                </div >
            );
        }
    }
    
    export default Test;
    

      

    React在进行组件更新时,如果发现这个组件是一个PureComponent,它会将组件现在的state和props和其下一个state和props进行浅比较,如果它们的值没有变化,就不会进行更新。

    类似于写了一个shouldComponentUpdate生命周期,判断nextProps和nextState是否有变化:

    import React from 'react';
    
    class Test extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                count: 0
            }
        }
        
        componentWillUpdate(nextProps, nextState) {
            console.log('componentWillUpdate')
        }
        
        componentDidUpdate(prevProps, prevState) {
            console.log('componentDidUpdate')
        }
        
        shouldComponentUpdate(nextProps, nextState) {
            // 如果没变化,就不渲染,否则重新渲染
            if (this.state.count === nextState.count) {
                return false
            }
            return true
        }
        
        render() {
            return ( 
                <div> 
                { this.state.count } 
                <button onClick = {
                    () => this.setState({ count: 1 }) }>点我</button> 
                </div>
            );
        }
    }
    
    export default Test;        
    

      

    【纯组件&非纯组件】

    纯组件其实类似于纯函数的概念。

    纯组件就是[单向],给定输入,就永远返回相同的输出,过程没有副作用与外部的状态依赖(props,state,context没有变化,则输出没有变化),也就代表着这个组件不需要重新渲染,从而提高性能收益。

    而很多个组件组成的比较复杂的组件树,则需要外部去维护它的状态,然后通过注入依赖,展示相对应的视图,这样可以维持组件树的纯净性。比较典型的解决方案是Redux,它把组件树看做一个状态树,分离逻辑与视图,再配合异步处理,就可以实现单向的数据流。类似的还有Cycle.js,有空学习。(#^.^#) (但还是附个链接: http://cyclejs.cn/#-%E7%BB%84%E4%BB%B6%E5%8C%96)

    【布局组件&内容组件】

    内容组件通常被约束在布局组件的占位中。抽离开来可以避免互相影响,提高可维护性。

    布局组件:Grid, Layout, HorizontalSplit……

    内容组件:Button, Label, Input……

    【表单组件】

    沿用通用的属性,保证兼容,减少代码重复,使用方便。

    组件受控。实际开发中非受控组件的场景非常少, 自定义组件应只提供完全受控表单组件,避免组件自身维护缓存状态。

    4、目录

     大牛推荐的多页面目录:

    src/
      components/       # 共享组件
      containers/
        Admin/          # 后台管理页面
          components/   # 后台特定的组件库
          LoginPage/
          index.tsx
          ...
        App/
          components/  # App特定的组件库
          LoginPage/   # App页面
          index.tsx
          stores.ts    # redux stores
        AnotherApp/    # 另外一个App页面
      hooks/
      ...
      app.tsx          # 应用入口
      anotherApp.tsx   # 应用入口
      admin.tsx        # 后台入口
    

      

     。。。。。。

    还有一些没用过的目录划分方式,有空学习。(#^.^#)

     5、模块

    每个目录都是一个模块,都应该有一个index的唯一出口文件来统一管理模块的导出(限定模块的可见性)

    (除了utils文件夹,它只是一块模块命名空间,因为它目录下是互不相关或不同类型的文件)

     相对路径不超过两级(即.././

    或者将相对路径转为绝对路径, 例如webpack中可以配置resolve.alias属性来实现(直接copy一下大佬的代码):

        ...
        resolve: {
          ...
          alias: {
            // 可以直接使用~访问相对于src目录的模块
            // 如 ~/components/Button
            '~': context,
          },
        }
    

      

    然后就可以:import { hide } from '~/utils/dom';

    6、组件拆分

    ①拆分为render方法,比如:

    // 生成数据列表工具栏
      const renderToolBar = () => {
        const toolBarList: ReactNode[] = [
          <Btn key="showMetrics" type="primary" onClick={showMetrics}>
            自定义指标
          </Btn>,
          rowKey ==='key' && <DownloadEfforts columnsData={columnsData} totalList={totalList} tableInfo={tableInfo} searchParams={searchParams} key="downloadExcel" dataType="effect"/>,
          rowKey ==='materialId' && <DownloadEfforts columnsData={columnsData} totalList={totalList} tableInfo={tableInfo} searchParams={searchParams} key="downloadExcel" dataType="materialRank"/>,
          (rowKey === 'adId' || rowKey === 'creativeId') && <DownloadEfforts columnsData={columnsData} tableInfo={tableInfo} searchParams={searchParams} key="downloadExcel" dataType="relation"/>,
        ];
        return toolBarList;
      };
    
    
      return (
        <BasisTable
           ...
            operateToolBar={() => renderToolBar()}
          />
      )
    

      

    但是这个方法只是在return处简化了代码,其实并没有真的实现组件的拆分。

    当代码行数超过300这个阈值,就要进行组件进一步拆分。

    ②拆分为组件

    • 纯UI渲染拆分为组件
    • 纯逻辑内容拆分到hooks中 || 拆分到高阶组件中
    • 两者皆有:将相关视图&逻辑都抽离,形成一个独立组件

    7、组件文档化

    https://storybook.js.org/

    推荐用storybook.js进行文档化,用过,还是挺好上手的,就不赘述了。

  • 相关阅读:
    Struts2笔记——ONGL表达式语言
    Struts2笔记——自定义拦截器
    Struts2笔记——Action校验器
    Struts2笔记——文件上传
    Struts2笔记——与ServletAPI解耦
    Struts2笔记——通配符和动态方法调用
    Struts2笔记——类型转换
    Struts2笔记——result结果类型
    MongoDB相关资料
    公开数据集
  • 原文地址:https://www.cnblogs.com/nangras/p/14859471.html
Copyright © 2011-2022 走看看