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时,其返回的组件内容是相同的,不纯净的组件会导致组件结果的难预测与难确定性
  • 分页组件
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)