1. 程式人生 > >React 折騰記 - (7) 基於React+Antd封裝聊天記錄(用到memo,lazy, Suspense)這些

React 折騰記 - (7) 基於React+Antd封裝聊天記錄(用到memo,lazy, Suspense)這些

前言

在重構的路上,總能寫點什麼東西出來

這東西不復雜,丟出來,一方面當做筆記,一方面可以給有需要的人;

用到技術點:

  • css module: 包括內建的繼承特性,類似less的巢狀寫法那種
  • 用到的react 16.6特性
    • lazy, Suspense來實現子元件的懶載入
    • memo讓函式式元件有PureComponent的特性(淺比較)
  • flexbox來佈局

效果圖


程式碼實現

index.js : 元件的主入口


import React, { PureComponent, lazy, Suspense } from
'react'; import { Avatar } from 'antd'; import style from './index.css'; // 渲染不同內容的元件 const LazyComponent = lazy(() => import('./RenderContent')); export default class index extends PureComponent { state = { loading: true, list: [ { time: '2018-11-12 15:35:15', avatar
: 'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-avatar/3_avatar.jpg?x-oss-process=image/resize,m_fixed,w_90,h_90/quality,q_90', nickname: '使用者甲', pos: 1, voice: 'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-chat/3_508340417_c84f79407f5bc16b9e7ee0373631cf35.aac', text
: '', }, { time: '2018-11-12 15:36:15', avatar: 'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-avatar/3_avatar.jpg?x-oss-process=image/resize,m_fixed,w_90,h_90/quality,q_90', nickname: '使用者甲', pos: 1, voice: 'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-chat/3_508340417_c84f79407f5bc16b9e7ee0373631cf35.aac', text: '', }, { time: '2018-11-12 15:37:15', avatar: 'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-avatar/3_avatar.jpg?x-oss-process=image/resize,m_fixed,w_90,h_90/quality,q_90', nickname: '卡布奇諾', pos: 2, voice: '', text: '該詞語多用於諷刺和揶揄調侃。也有送快遞、查水電氣、社群送溫暖等引申說法。例如:(1)有人在網路上發表了不合乎相關法律法規或者破壞社會穩定和諧等訊息而被警方捕;(2)在貼吧或論壇裡擁有刪帖許可權的大小吧主,檢查貼吧裡是否存在灌水的帖子或跟帖,遇到就進行刪除的行為。', }, { time: '2018-11-12 15:38:15', avatar: 'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-avatar/3_avatar.jpg?x-oss-process=image/resize,m_fixed,w_90,h_90/quality,q_90', nickname: '卡布奇諾', pos: 2, voice: '', img: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3040115650,4147729993&fm=26&gp=0.jpg', text: '該詞語多用於諷刺和揶揄調侃。也有送快遞、查水電氣、社群送溫暖等引申說法。例如:(1)有人在網路上發表了不合乎相關法律法規或者破壞社會穩定和諧等訊息而被警方捕;(2)在貼吧或論壇裡擁有刪帖許可權的大小吧主,檢查貼吧裡是否存在灌水的帖子或跟帖,遇到就進行刪除的行為。', }, { time: '2018-11-12 15:39:15', avatar: 'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-avatar/3_avatar.jpg?x-oss-process=image/resize,m_fixed,w_90,h_90/quality,q_90', nickname: '卡布奇諾', pos: 2, voice: '', img: 'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3040115650,4147729993&fm=26&gp=0.jpg', }, ], }; static getDerivedStateFromProps(nextProps, prevState) { const { data } = nextProps; if (!data || !Array.isArray(data) || data.length <= 0) { return null; } return { list: data, }; } // 喚醒子元件的回撥過程 wakeUpLazyComponent = () => { return <div>loading.....</div>; }; render() { const { list, loading } = this.state; const isRender = list && list.length > 0; return ( <ul className={style['list-wrapper']}> {isRender && list.map((item, listIndex) => { return ( <Suspense fallback={this.wakeUpLazyComponent()} key={listIndex}> <li className={style['list-item']}> <span className={style['time']}>{item.time ? item.time : '時間佔位符'}</span> <div className={ item.pos === 1 ? style['list-item-horizontal'] : style['list-item-horizontal-reverse'] } > <Avatar shape="square" src={ item.avatar ? item.avatar : 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png' } /> <div className={ item.pos === 1 ? style['content-wrapper-flex'] : style['content-wrapper'] } > <p className={item.pos === 1 ? style.nickname : style['nickname-right']}> {item.nickname ? item.nickname : '使用者暱稱佔位符'} </p> <div className={style.content}> <LazyComponent {...item} /> </div> </div> </div> </li> </Suspense> ); })} </ul> ); } } 複製程式碼

RenderContent.js:渲染對話條目


import React, { memo } from 'react';
import style from './index.css';

// antd 圖文元件
import { Card } from 'antd';
const { Meta } = Card;

const RenderContent = memo(props => {
  if (props.img && props.text) {
    return (
      <Card
        hoverable
        style={{ width: 300 }}
        cover={<img alt="example" src={props.img ? props.img : ''} />}
      >
        <Meta description={props.text ? props.text : ''} />
      </Card>
    );
  }
  if (props.img) {
    return (
      <div className={style['img-wrapper']}>
        <img className={style['img-preview']} src={props.img ? props.img : ''} alt="photos" />
      </div>
    );
  }
  if (props.text) {
    return <div className={style['bubble']}>{props.text}</div>;
  }
  if (props.voice) {
    return <audio src={props.voice ? props.voice : ''} controls />;
  }
  return null;
});

export default RenderContent;


複製程式碼

index.css : 樣式

composescss module能識別的特殊欄位,用於繼承其他樣式的

/* 列表全域性樣式 */
.list-wrapper {
  list-style-type: none;
  list-style: none;
  padding-left: 0;
}

/* 列表基本樣式 */
.list-item {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-content: flex-start;
  margin: 15px 0;
}

/* 水平展開 */
.list-item-horizontal {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
}

/* 右對齊方式變化 */
.list-item-horizontal-reverse {
  composes: list-item-horizontal;
  flex-direction: row-reverse;
}

/* 使用者名稱 */
.nickname {
  font-size: 12px;
  padding:0 10px;
  color: #8a8484;
  margin-bottom: 5px;
}

/* 使用者名稱右對齊 */
.nickname-right {
  composes: nickname;
  text-align: right;
}

/* 時間樣式 */
.time {
  text-align: center;
  background-color: #cecece;
  color: #fff;
  border-radius: 3px;
  align-self: center;
  font-size: 12px;
  padding: 5px;
  margin:5px;
}

/* 內容區域 */
.content-wrapper {
  margin: 0 15px;
}

/* 彈性伸縮 */
.content-wrapper-responsive {
  flex: 1;
}

/* 氣泡文字 */
.bubble {
  padding: 8px;
  color: #333;
  max-width: 300px;
  line-height: 1.5;
  background-color: #a7e544;
  border-radius: 3px;
  text-align: left;
  text-indent: 10px;
  margin:0 3px;
}

/* 圖片預覽 */
.img-wrapper {
  box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14),
    0px 2px 1px -1px rgba(0, 0, 0, 0.12);
  border-radius: 3px;
  padding: 5px;
}

.img-preview {
  max-width: 200px;
}


複製程式碼

使用姿勢

接受的props只有一個 data, 格式是[Obj](陣列物件);

條目欄位解釋

  • time: 時間
  • avatar: 使用者頭像
  • nickname:使用者暱稱
  • pos: 1 (1在左側渲染,2在右側渲染)
  • voice(音訊)/text(文字內容)/ img(圖片內容) => voice(唯一)/** text + img** / text

  {
    time: '2018-11-12 15:35:15',
    avatar:
      'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-avatar/3_avatar.jpg?x-oss-process=image/resize,m_fixed,w_90,h_90/quality,q_90',
    nickname: '使用者甲',
    pos: 1,
    voice:
      'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-chat/3_508340417_c84f79407f5bc16b9e7ee0373631cf35.aac',
    text: '',
    img:
          'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3040115650,4147729993&fm=26&gp=0.jpg'
  },

複製程式碼

總結

  • 上拉下拉不考慮,因為沒這個需求,資料量不大..一個人的留言十幾條最多了
  • 有需要的可以自行新增,也就是多暴露兩個事件給外部(判斷滾動的高度)

有不對之處請留言,會及時修正,謝謝閱讀...