preface

On the way to refactoring, there’s always something to write, something that’s not complicated, something that’s useful, right

On the one hand as notes, on the other hand can be given to people in need; Interested partners can have a look.

rendering

Implemented functions

  • Rendering support pictures, text, text
  • Support for deleting entries (and giving parent callbacks)

Technical points used:

  • css module: includes built-in inheritance features, similarlessThe nested writing method of
  • Use of16.6 the reactfeatures
    • lazy, SuspenseTo implement lazy loading of sub-components
    • memoLet the functional component havePureComponentCharacteristics of (shallow comparison)
  • flexboxTo layout
  • With thelodashtheisEqualTo compare objects in depth forgetDerivedStateFromProps(Avoid updating every timestate)

Code implementation

index.js: Main entry of a component


import React, { PureComponent, lazy, Suspense } from 'react';
import { Avatar, Icon, Popover } from 'antd';
import style from './index.css';

// Lodash deep comparison
import isEqual from 'lodash/isEqual';

// Render components with different content
const LazyComponent = lazy((a)= > import('./RenderContent'));

export default class index extends PureComponent {
  state = {
    deleteBtnSpin: false.loading: true.list: [{time: 'the 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/qual ity,q_90'.nickname: 'User A'.pos: 1.voice:
          'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-chat/3_508340417_c84f79407f5bc16b9e7ee0373631cf35.aac'.text: ' '}, {time: 'the 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/qual ity,q_90'.nickname: 'User A'.pos: 1.voice:
          'https://sx-stag.oss-cn-shenzhen.aliyuncs.com/user-chat/3_508340417_c84f79407f5bc16b9e7ee0373631cf35.aac'.text: ' '}, {time: 'the 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/qual ity,q_90'.nickname: 'Cappuccino'.pos: 2.voice: ' '.text:
          'The term is often used sarcastically and teasingly. There are also express delivery, check water and electricity, community to send warmth and other extended statements. For example :(1) some people are arrested by the police for publishing information that is not in accordance with relevant laws and regulations or undermines social stability and harmony; (2) The owner of the small or small bar who has the permission to delete posts in the post bar or forum, check whether there is any flooded posts or comments in the post bar, and delete them when they meet. '}, {time: 'the 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/qual ity,q_90'.nickname: 'Cappuccino'.pos: 2.voice: ' '.img:
          'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3040115650, & FM = 26 & gp = 0. 4147729993 JPG'.text:
          'The term is often used sarcastically and teasingly. There are also express delivery, check water and electricity, community to send warmth and other extended statements. For example :(1) some people are arrested by the police for publishing information that is not in accordance with relevant laws and regulations or undermines social stability and harmony; (2) The owner of the small or small bar who has the permission to delete posts in the post bar or forum, check whether there is any flooded posts or comments in the post bar, and delete them when they meet. '}, {time: 'the 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/qual ity,q_90'.nickname: 'Cappuccino'.pos: 2.voice: ' '.img:
          'https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=3040115650, & FM = 26 & gp = 0. 4147729993 JPG',}]};static getDerivedStateFromProps(nextProps, prevState) {
    const { data } = nextProps;

    // If the props are the same as the cache state, the state is not updated
    if (isEqual(prevState.prevData, nextProps.data)) {
      return null;
    }
    // If no props is passed, too
    if(! data || !Array.isArray(data) || data.length <= 0) {
      return null;
    }
    return {
      list: data,
      prevData: nextProps.data,
    };
  }

  // Wake up the child component's callback process
  wakeUpLazyComponent = (a)= > {
    return <div>loading.....</div>;
  };

  // Hover items to display the delete button
  showOperatBtn = index= > {
    let tmpList = [...this.state.list];
    tmpList = tmpList.map((item, innerIndex) = > {
      if (index === innerIndex) {
        item.operatBtn = true;
      } else {
        item.operatBtn = false;
      }
      return item;
    });
    this.setState({ list: tmpList });
  };

  // Close the action button
  hideOperatBtn = index= > {
    let tmpList = [...this.state.list];
    tmpList = tmpList.map((item, innerIndex) = > {
      item.operatBtn = false;
      return item;
    });
    this.setState({ list: tmpList });
  };

  // Delete this reply
  deleteCurrentReplay = (index, itemInfo) = > {
    let tmpList = [...this.state.list];
    tmpList.splice(index, 1);
    this.setState({ list: tmpList });
    // A callback to the parent that returns all information about the item, and then performs interface operations externally
    if (this.props.deleteItem) {
      this.props.deleteItem(itemInfo); }}; render() {const { list, deleteBtnSpin } = this.state;
    // Whether to display the operation area
    const { operate } = this.props;
    // Render component preconditions
    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']} onMouseOver={() => this.showOperatBtn(listIndex)} onMouseLeave={() => this.hideOperatBtn(listIndex)} > <span className={style['time']}>{item.time ? Item. time: 'time placeholder '}</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 : 'User nickname placeholder '} </p> <div className={style.content}> <LazyComponent {... item} /> </div> </div> {!! operate && item.operatBtn ? (<Popover content={' This operation deletes the record '} title=" Be careful!" onMouseEnter={() => { this.setState({ deleteBtnSpin: true }); }} onMouseLeave={() => { this.setState({ deleteBtnSpin: false }); }} > <Icon type="delete" spin={deleteBtnSpin} style={{ fontSize: 24, alignSelf: 'flex-end', color: `${this.state.deleteBtnSpin ? '#ec1414' : '#1890ff'}`, }} onClick={() => this.deleteCurrentReplay(listIndex, item)} /> </Popover> ) : null} </div> </li> </Suspense> ); })} </ul> ); }}Copy the code

RenderContent.jsRender the dialog entry


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

// AntD graphics component
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;


Copy the code

index.cssStyle:

composesiscss moduleA special field that can be recognized to inherit from other styles

/* List global style */
.list-wrapper {
  list-style-type: none;
  list-style: none;
  padding-left: 0;
}

/* List base style */
.list-item {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  align-content: flex-start;
  margin: 15px 0;
}

/* Horizontal expansion */
.list-item-horizontal {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
}

/* The right alignment changes */
.list-item-horizontal-reverse {
  composes: list-item-horizontal;
  flex-direction: row-reverse;
}

/* User name */
.nickname {
  font-size: 12px;
  padding:0 10px;
  color: #8a8484;
  margin-bottom: 5px;
}

/* Right-align the user name */
.nickname-right {
  composes: nickname;
  text-align: right;
}

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

/* Content area */
.content-wrapper {
  margin: 0 15px;
}

/* Elastic expansion */
.content-wrapper-responsive {
  flex: 1;
}

/* Bubble text */
.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;
}

/* Image preview */
.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;
}


Copy the code

Use the pose

To accept theprops

  • dataThe format is[Obj](array object);
  • operate: Boolean value (whether operation area is displayed)

List entry field explanation

  • Time: time
  • Avatar: indicates the user’s avatar
  • Nickname: nickname of the user
  • Pos: 1 (1 rendered on the left,2 rendered on the right)
  • Voice /text/img => voice /text + img /text

  {
    time: 'the 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/qual ity,q_90'.nickname: 'User A'.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, & FM = 26 & gp = 0. 4147729993 JPG'
  },

Copy the code

conclusion

  • Pull down do not consider, because there is no demand for this, the amount of data is not large, a person’s message more than ten or twenty to the top
  • If necessary, you can add it yourself, that is, expose two more events to the outside (judge the scrolling height).

If there is something wrong, please leave a message and correct it in time. Thank you for reading.