React笔记(五) 组件化与简单封装

React笔记(五)

1.组件化
  • React应用采用基于组件的架构方式,也就是说可以将一个复杂的页面分解成一个个较简单的组件来实现。但组件在开发时,常常会遇到一些问题,比如为单一组件赋予了过多的指责。这在项目上是可行的,但如果需要修改现有功能,或者创建新功能,就大大增加了工作量。

    export default class Demoe extends Component {
      state={
        count:0
      };
      render() {
        return (
          <>
          <div>{this.state.count}</div>
          <ControlCount parent={this} mode='add'/>
          <ControlCount  parent={this}  mode='sub'/>
          </>
        )
      }
    }
    class ControlCount extends Component{
      render(){
        if (this.props.mode =='add'){
          return <button onClick={()=>
            {
            this.props.parent.setState(
              (pre)=>({count:pre.count+1})
              )
            }
          }>加一</button>
        }
        else{
          return <button onClick={()=>
            {
            this.props.parent.setState(
              (pre)=>({count:pre.count-1})
              )
            }
          }>减一</button>
        }
      }
    }
    

    上面示例中,将两个按钮抽取成为两个组件,实现了应用的组件化,但如果需要增加功能,比如说,增加乘法与除法;又或者在其他地方需要使用此组件,但需要将+1变成+2。这个时候就需要做一些比较大的改动。

  • 所以作为组件需要符合以下几点要求

    • 单一责任 也就是说让一个组件尽可能的只执行一个任务,例如请求远程数据,又或者渲染表数据等。具有单一职责的组件,相对于其他组件,更容易编码,修改与测试。并且,多重责任的组件也会使得修改组件时副作用更难预测和控制,也就是当需要修改一处时,可能会在无意识的情况下修改了其他的部分
    • 封装 通过封装来减小耦合度。并且在实际应用时,可以实现重用性,与可替换性。整个组件由父组件传递进的props进行控制,在props中可以传递字面量,对象,函数,甚至一个组件。另外,封装后的组件也要实现可组合性,其可以类似积木一般,一块一块组合起来。
    • 纯净 这里的纯净代表着纯函数的纯,也就是当组件接收到相同的props时,其返回的组件内容是相同的,不纯净的组件会导致组件结果的难预测与难确定性
  • 在实际开发中,存在有很多组件库帮助我们实现了组件的封装,例如Material-UI:当下流行的 React UI 框架 (mui.com)Ant Design - 一套企业级 UI 设计语言和 React 组件库Home - Fluent UI (microsoft.com)等。这些组件库帮助我们不需要手动去封装组件,但也根据实际应用需要而基于这些组件库去做二次封装。

  • 简单封装一些组件

    • 分页组件

      export default class Demo extends Component {
       render(){
         var list = [];
         for (let index = 0; index < 100; index++) {
           list.push({title:`标题${index}`,content:`xxxxxxxx${index}`});
         }
         return <PagesList list={list} currentPage={1}/>
       }
      }
      class PagesList extends Component{
      
        constructor(props){
          super(props);
          //定义当前页码位置
          this.state = {
            currentPage:props.currentPage
          };
        }
      
        render(){
          const {list} = this.props;
          const {currentPage} = this.state;
      
          //获取总页码数,并准备渲染
          const totalPage = list.length/10;
          var pages =[];
          for (let index = 1; index <= totalPage; index++) {
            pages.push(index);
          }
      
          //展示的列表
          const showList = list.slice((currentPage-1)*10,10*currentPage);
      
          return (
            <div>
              {/* 展示列表 */}
              <div style={{marginBottom:5}}>
                {showList.map((e)=>{
                  return <div className='message'><h3>{e.title}</h3><p>{e.content}</p></div>
                })}
              </div>
                <div>
                  {/* 判断是否展示上一页 */}
                    {currentPage>1&&<a className='pages' onClick={
                      ()=>{
                          this.setState(
                            (pre)=>({currentPage:pre.currentPage-1})
                          )
                        }
                      }
                      >上一页</a>}
                  {/* 展示页码,并高亮当前选择的页 */}
                    {
                      pages.map((e)=>{
                        return <a className={e==currentPage?'pages active':'pages'} onClick={()=>this.setState({currentPage:e})}>{e}</a>
                      })
                    }
                  {/* 判断是否展示下一页 */}
                    {currentPage<totalPage&&<a className='pages' onClick={
                      ()=>{
                          this.setState(
                            (pre)=>({currentPage:pre.currentPage+1})
                          )
                        }
                      }>下一页</a>}
                </div>
            </div>
          )
        }
      }
      
      .message{
        border:1px solid black;
      }
      .pages{
        padding: 5px;
        border:1px solid blue;
      }
      .active{
        background-color: gold;
      }
      
    • 消息展示组件

      export default class Demo extends Component {
        render() {
          var list=[];
          for (let index = 0; index < 100; index++) {
            list.push(`xxxxxxxx${index}`);
          }
          return <ShowNewMessage list={list}/>
        }
      }
      class ShowNewMessage extends Component {
        constructor(props) {
          super(props);
          //是否显示新消息部分
          this.state = {
            contentVis: false,
          }
        }
        render() {
          const { list } = this.props;
          const {contentVis} = this.state;
          return (<>
            <button onClick={() => { this.setState({ contentVis: !contentVis }) }} className='open'>打开消息</button>
            {/* 通过状态控制消息展示 */}
            {contentVis && <><div className='messages'>
              {
                list.map((e) => {
                  return <p className='message'>{e}</p>
                })
              }
            </div>
            {/* 查看全部跳转新页 */}
            <button onClick={()=>{window.open('https://www.baidu.com')}} className='open'>查看全部</button>
            </>}
          </>)
        }
      }
      
      
      .message{
        border:1px solid black;
      }
      .messages{
        width: 150px;
        height: 200px;
        overflow-y: scroll;
      }
      .open{
        width: 150px;
        border:1px solid black;
      }
      

参考文章

7 可靠 React 组件的架构属性 (dmitripavlutin.com)

React组件应该如何封装?_YvetteLau的博客-CSDN博客

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值