Project creationReact Experience out of the box

Implementation steps – Directory definition

Antd. design-Pro based scaffolding

  • inlayoutsAdd chat interface layout
  • inpagesDirectory adds chat interface

File structure

├─ SRC │ ├─ Bass │ ├─ layouts │ ├─ Bass │ ├. JSX # Bass │ ├─ Pages │ ├─ Im │ │ ├─ chat │ │ ├─ ├.jsx # Im │ │ ├─ chat │ │ ├─ JSX # Im │ │ ├─ chat │ │ ├─ JSX #Copy the code

Configuring access Routesconfig/routes.js

{
  path: '/im'.name: 'im'.icon: 'wechat'.// Display ICONS
  routes: [{path: '/im'.// Access the routing address
      component: '.. /layouts/ChatLayout'.// The chat interface uses the chat layout
      routes: [{path: '/im'.// Initialize the interface
          component: './Im'}, {path: '/im/chat'.// The specific chat interface is displayed
          name: 'chat'.component: './Im/chat'.// Corresponding component},],},],},Copy the code

Add Internationalizationlocales/zh-CN/menu.js

  'menu.im': 'Instant Messaging'.'menu.chat': 'chat'.Copy the code

Implementation steps – Mock data preparation

Use DVA status data management

Dva for those unfamiliar with React, see introduction to the common development framework

inmodelsDirectory creationchat.js

const ChatModel = {
  namespace: "chat".state: {
    // The current chat object
    chatUserInfo: {},
    // Enter the chat information
    content: "".// Chat details
    messageList: [{msgId: "7751131831315698898".sendId: "775113183131074580".content: "Have you eaten?"}, {msgId: "7751133655565656565".sendId: "801901013480247300".content: "The water of the Yellow River comes from heaven."],},// List of recent chats
    chatRecordList: [{msgId: "775113183131069599".sendId: "801901013480247300".receiveId: "775113183131074580".type: "1".chatType: "1".sendTime: "2021-03-09".content: "The water of the Yellow River comes from heaven.",}]},effects: {},

  reducers: {
    // Currently chat with that
    chatCurrentUser(state, { payload: { chatUserInfo } }) {
      return {
        ...state,
        chatUserInfo,
      };
    },

    // Refresh the chat list
    refreshChatList(state, { payload: { messageList } }) {
      return {
        ...state,
        messageList: messageList,
      };
    },

    // When the input message changes
    chatInputMessageChange(state, { payload: { message } }) {
      return {
        ...state,
        content: message, }; }},subscriptions: {
    setup({ history }) {
      history.listen(({ pathname, search }) = >{}); ,}}};export default ChatModel;
Copy the code

Implementation steps – Layout

ChatLayout code

import { Link } from "umi";
import { connect } from "dva";

import ChatRecordItem from "@/components/ChatRecordItem";

import styles from "./ChatLayout.less";

const ChatLayout = ({ dispatch, children, chat }) = > {
  const { chatUserInfo, chatRecordList } = chat;

  // Click to switch the current chat object
  // Define 'chat/chatCurrentUser' in model/chat
  const onChangeChatCurrentUser = (item) = > {
    dispatch({
      type: "chat/chatCurrentUser".payload: {
        chatUserInfo: item,
      },
    });
  };
  return (
    <div className={styles["chat-layout-container"]} >
      <div className={styles["chat-message-list"]} >
        {chatRecordList.map((item) => {
          return (
            <Link to="/im/chat" key={item.msgId}>
              <ChatRecordItem
                {. item} // Select the chat objectselected={item.sendId= = =chatUserInfo.sendId}
                onClick={()= > onChangeChatCurrentUser(item)}
              />
            </Link>
          );
        })}
      </div>
      <div className={styles["chat-message-content"]} >{children}</div>
    </div>
  );
};

export default connect(({ chat }) = > ({
  chat,
}))(ChatLayout);
Copy the code

ChatLayout code description

No chat object is selected to display
import { Card, Empty } from "antd";

export default() = > (<Card>
    <Empty description="Please choose who to talk to." />
  </Card>
);
Copy the code
  • antd.design-pro Layoutdefine
  • Create a separate chat layout
  • inroute.jsThe use of
    • Configuring access Routing ->config/routes.js
Chat layout
  • The left side displays the latest chat history. Click the latest chat object. The right side displays the details of the chat object

ChatRecordItemDisplays the most recent chat history for each day for the encapsulated component

  • InitUserList is mock data that stores mock user information (user name, avatar).

    export const initUserList = [
      {
        userId: "801901013480247300".userName: "Li bai".avatar:
          "https://gitee.com/shizidada/moose-resource/raw/master/blog/default-avatar.png",},];Copy the code
  • Netty-socketio is integrated with SpringBoot

The classNames module can be built to add styles using className

import { Avatar, Divider } from "antd";
import { initUserList } from "@/mock/userList";

import cls from "classnames";

import styles from "./index.less";

const ChatRecordItem = ({ sendId, sendTime, content, selected, onClick }) = > {
  const [userInfo] = initUserList.filter((item) = > item.userId === sendId);
  if(! userInfo)return null;
  let selectedClassName = styles["chat-record-item-selected"];
  return (
    <div>
      <div
        className={cls(styles["chat-record-item"{[],selectedClassName]: selected})},onClick={onClick}
      >
        <div className={styles["chat-user-avatar"]} >
          <Avatar src={userInfo.avatar} />
        </div>
        <div className={styles["chat-user-info"]} >
          <div className={styles.top}>
            <p className={styles["chat-user-name"]} >
              {userInfo.userName || ""}
            </p>
            <span className={styles.time}>{sendTime}</span>
          </div>
          <div className={styles["chat-message-detail-item"]} >
            <p className={styles["chat-message-detail"]} > {content}</p>
          </div>
        </div>
      </div>
      <Divider style={{ margin: 0}} / >
    </div>
  );
};

export default ChatRecordItem;
Copy the code

chat

Select chat object to display

  • Im -> chat -> index.jsx

    Code address gitee.com/shizidada/m…

Details shown

{
  messageList.map((item, index) = > {
    returnitem.sendId ! == userId ? (<div className={styles["chat-item"]} key={item.msgId || index} >
        <div className={styles["chat-receiver"]} >
          {/* receiver */}
          <div className={styles["avatar-wrap"]} >
            <div className={styles.avatar}>
              <Avatar
                size="large"
                style={{ backgroundColor: "#005EFF", verticalAlign: "middle}} ">
                {toUserName}
              </Avatar>
            </div>
          </div>
          <div className={styles.content}>{item.content}</div>
        </div>
      </div>
    ) : (
      <div className={styles["chat-item"]} key={item.messageId || index} >
        <div className={styles["chat-sender"]} >
          {/* sender */}
          <div className={styles.content}>{item.content}</div>
          <div className={styles["avatar-wrap"]} >
            <div className={styles.avatar}>
              <Avatar
                size="large"
                style={{ backgroundColor: "#005EFF", verticalAlign: "middle}} ">
                {userName}
              </Avatar>
            </div>
          </div>
        </div>
      </div>
    );
  });
}
Copy the code

You can componentize display sent messages and received messages

Chat operation

<div className={styles["chat-input-area"]} ><Row>
    <Input.TextArea
      placeholder="Please enter a message"
      autoSize={{ minRows: 4.maxRows: 5 }}
      value={content}
      onChange={(e)= >
        dispatch({
          type: "chat/chatInputMessageChange",
          payload: {
            message: e.target.value,
          },
        })
      }
    />
  </Row>
  <Row type="flex" justify="end" style={{ marginTop: 10.marginRight: 10}} >
    <Col>
      <Button type="primary" onClick={onSendMessage} disabled={! content}>send</Button>
      {/* for test */}
      {/* <Button type="primary" onClick={onMessageScroll}>rolling</Button>* /}</Col>
  </Row>
</div>
Copy the code

Send a message

  • You have to choose who to talk to
  • Content must be entered
  • Trigger ChatModel to define reducers; Add a message to refresh the current view
const onSendMessage = () = > {
  if(! receiveId) { message.error("Please choose who to talk to.");
    return;
  }

  if(! content) {return;
  }

  let messageTemplate = {
    type: "MS:TEXT".chatType: "CT:SINGLE",
    content,
    sendId: userId,
    receiveId: receiveId,
  };
  const temp = messageList.concat();
  temp.push(messageTemplate);
  dispatch({
    type: "chat/refreshChatList".payload: {
      messageList: temp,
    },
  });
  dispatch({
    type: "chat/chatInputMessageChange".payload: {
      message: null,}}); };Copy the code

Over the message container, automatically scroll to the bottom

  • It can be implemented using native JS
  • The current use ofreact-scrollModule implements

usereact-scroll

  • npm install react-scroll –save

  • Add the react scroll code

import { Element } from "react-scroll";
Copy the code
  • Add after iterating through the message
<Element name="bottomElement"></Element>
Copy the code

  • callreact-scroll API
import { scroller } from "react-scroll";

// scrollId defines Element name
scroller.scrollTo(`scrollId`, {
  duration: 800.delay: 0.smooth: true.containerId: `containerId`.offset: 50});Copy the code

encapsulationreact-scroll API

  • utils/scroller.js
import { scroller } from "react-scroll";

export const scrollToBottom = (scrollId, containerId) = > {
  scroller.scrollTo(scrollId, {
    duration: 800.delay: 0.smooth: true.containerId: containerId,
    offset: 50}); };Copy the code

More react – scroll API reference react – scroll module documentation www.npmjs.com/package/rea…

use

  • Select the chat object callscrollToBottom
  • Called after sending the message is completescrollToBottom
const onMessageScroll = () = > {
  scrollToBottom("bottomElement"."chatItems");
};

// Send a message. dispatch({type: 'chat/chatInputMessageChange'.payload: {
      message: null,}}); onMessageScroll();/ / call scrollToBottom}; .// Go to the page
useEffect(() = > {
  // No chat object is selected, and the chat initialization screen is displayed
if(! receiveId) { history.replace({pathname: '/im' });
    return;
  }
  onMessageScroll();
  return () = >{}; } []);Copy the code