@xonar
А смысл?

Как навесить класс при событие на React'е?

Здравствуйте.

Есть задачка, когда курсор мышки попадает на элемент с классом old-chat или на класс header, то этому элементу и элементу с классом header навешивается дополнительный класс open-show.

Но, на реакте это не так легко лично для меня оказалось, завис неплохо так. Буду рад помощи.

Застрял я тут

componentOpenChat() {
    const openchat = document.querySelector(".old-chat");
      openchat.addEventListener("onmouseover", (e) => {
        e.preventDefault();
        openchat.classList.add("open-show");
    });
  }


Полный код

/* @flow */
import React from "react";
import io from "socket.io-client";
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import { compose, onlyUpdateForKeys } from "recompose";
import { stringify as b } from "rebem-classname";
import Scrollbars from "react-custom-scrollbars";
import { selectors as userSelectors } from "../user/logicBundle";
import { addMessage, deleteMessage, setMessages, addClanMessage, setClanMessages, sendMessage, sendClanMessage, apiBanChat, apiDeleteMessage, selectors as chatSelectors } from "../Chat/logicBundle";
import Message from "./Message";
import Coupon from "./Coupon";
import Ban from "../Chat/Ban";
import "./Chat.scss";
import type { UserType } from "../user/types";

const block = "old-chat";

class OldChat extends React.PureComponent {
  constructor(props: Object) {
    super(props);
    this.onChatNewMessage = (message: Object) => {
      const { actions } = this.props;
      const { isClan } = this.state;
      let isScroll = false;
      if (
        this.scrollbar.getScrollHeight() -
        this.scrollbar.getScrollTop() -
        this.scrollbar.getClientHeight() <=
        30
      ) {
        isScroll = true;
      }
      actions.addMessage(message);
      if (!isClan && isScroll && this.scrollbar) {
        this.scrollbar.scrollToBottom();
      }
    };
    this.onChatDeleteMessage = (messageId: number) => {
      const { actions } = this.props;
      actions.deleteMessage(messageId);
    };
    this.onChatNewClanMessage = (message: Object) => {
      const { actions } = this.props;
      const { isClan } = this.state;
      let isScroll = false;
      if (
        this.scrollbar.getScrollHeight() -
        this.scrollbar.getScrollTop() -
        this.scrollbar.getClientHeight() <=
        30
      ) {
        isScroll = true;
      }
      actions.addClanMessage(message);
      if (isClan && isScroll && this.scrollbar) {
        this.scrollbar.scrollToBottom();
      }
    }
    };

  state: {
    isShow: boolean,
    isClan: boolean,
    message: string,
  } = {
    isShow: true,
    isClan: false,
    message: "",
  };

  componentDidMount() {
    let { chat: socket } = window.socket;
    if (!socket) {
      window.socket.chat = io("/chat", window.socket.opts);
      socket = window.socket.chat;
    }

    const { actions } = this.props;
    const { isClan } = this.state;

    socket.on("connect", () => {
      socket.emit("chat:join", (messages: Object[]) => {
        actions.setMessages(messages);
        if (!isClan && this.scrollbar) {
          this.scrollbar.scrollToBottom();
        }
      });
    });
    socket.on("chat:newMessage", this.onChatNewMessage);
    socket.on("chat:deleteMessage", this.onChatDeleteMessage);
  }

  componentWillReceiveProps(nextProps) {
    const { chat: socket } = window.socket;
    const { user, actions } = nextProps;
    if (user.id && user.id !== this.props.user.id && user.clan) {
      socket.emit("chat:clanJoin", (messages: Object[]) => {
        actions.setClanMessages(messages);
        if (this.state.isClan && this.scrollbar) {
          this.scrollbar.scrollToBottom();
        }
      });
      socket.on("chat:newClanMessage", this.onChatNewClanMessage);
    }
  }

  componentWillUnmount() {
    const { chat: socket } = window.socket;
    socket.off("chat:newMessage", this.onChatNewMessage);
    socket.off("chat:deleteMessage", this.onChatDeleteMessage);
    socket.off("chat:newClanMessage", this.onChatNewClanMessage);
  }

  componentOpenChat() {
    const openchat = document.querySelector(".old-chat");
      openchat.addEventListener("onmouseover", (e) => {
        e.preventDefault();
        openchat.classList.add("open-show");
    });
  }

  onChatNewMessage: Function;
  onChatDeleteMessage: Function;
  onChatNewClanMessage: Function;

  props: {
    handleToggle: Function,
    user: UserType,
    messages: Object[],
    clanMessages: Object[],
    actions: Object,
  };

  handleChange = (e: Object) => {
    this.setState({ [e.target.name]: e.target.value });
  };

  handleSendMessage = (e: Object) => {
    e.preventDefault();
    const { isClan, message } = this.state;
    if (!isClan) {
      this.props.actions.sendMessage(message);
    } else {
      this.props.actions.sendClanMessage(message);
    }
    this.setState({ message: "" });
  };

  handleToggle = (force: boolean, isClan: boolean) => () => {
    this.setState({
      isShow: force || !this.state.isShow,
      isClan,
    });
    setTimeout(() => this.scrollbar && this.scrollbar.scrollToBottom(), 100);
  };

  render() {
    const { user, messages: _messages, clanMessages, actions } = this.props;
    const { isShow, isClan, message } = this.state;

    const messages = !isClan ? _messages : clanMessages;

    return (
      <aside className={b({ block })}>
        <div className={b({ block, elem: "container", mods: { show: isShow } })}>
          <div className={b({ block, elem: "head" })}>
            <span>{!isClan ? "Чат" : "Чат клана"}</span>

            <div className={"navbar__online"}>
              <i className="fa fa-users" />
              <div>Online: </div>
            </div>
            <button className={b({ block, elem: "item" })} onClick={this.handleToggle(true, false)}>
              <i className="fa fa-comments" />
            </button>
            {user.clan && (
              <button className={b({ block, elem: "item" })} onClick={this.handleToggle(true, true)}>
                <i className="fa fa-users" />
              </button>
            )}
            <button className={b({ block, elem: "hide-btn" })} onClick={this.handleToggle(false, isClan)}>
              <i className="fa fa-double-chevron-right" />
            </button>
          </div>
          <div className={b({ block, elem: "messages" })}>
            <Scrollbars
              renderTrackHorizontal={() => <div style={{ display: "none" }} />}
              ref={scrollbar => { this.scrollbar = scrollbar; }}
            >
              <div className={b({ block, elem: "messages-container" })}>
                {messages.map((_message: Object) => {
                  if (_message.is_coupon) {
                    return (
                      <Coupon key={_message.id} message={_message.message} />
                    );
                  }
                  if (_message.is_ban) {
                    return (
                      <Ban key={_message.id} message={_message.message} />
                    );
                  }
                  return (
                    <Message
                      key={_message.id}
                      id={_message.id}
                      user={_message.user}
                      message={_message.message}
                      showControls={!isClan && (user.is_admin || user.is_moderator)}
                      banChat={actions.apiBanChat}
                      deleteMessage={actions.apiDeleteMessage}
                    />
                  );
                })}
              </div>
            </Scrollbars>
          </div>
          <form className={b({ block, elem: "send" })} onSubmit={this.handleSendMessage}>
            <input
              className={b({ block, elem: "send-input" })}
              type="text"
              placeholder="Введите сообщение..."
              name="message"
              value={message}
              onChange={this.handleChange}
            />
            <button className={b({ block, elem: "send-btn" })} type="submit">
              <i className="fa fa-comment-o" />
            </button>
          </form>
        </div>
        <div className={b({ block, elem: "bar" })}>
          <button className={b({ block, elem: "item" })} onClick={this.handleToggle(true, false)}>
            <i className="fa fa-comments" />
          </button>
          {user.clan && (
            <button className={b({ block, elem: "item" })} onClick={this.handleToggle(true, true)}>
              <i className="fa fa-users" />
            </button>
          )}
        </div>
      </aside>
    );
  }
}

export const enhance = compose(
  connect(
    state => ({
      user: userSelectors.getUser(state),
      messages: chatSelectors.getMessages(state),
      clanMessages: chatSelectors.getClanMessages(state),
    }),
    dispatch => ({
      actions: bindActionCreators({
        addMessage,
        deleteMessage,
        setMessages,
        addClanMessage,
        setClanMessages,
        sendMessage,
        sendClanMessage,
        apiBanChat,
        apiDeleteMessage,
      }, dispatch),
    })
  ),
  onlyUpdateForKeys(["user", "messages", "clanMessages"])
);

export default enhance(OldChat);

  • Вопрос задан
  • 266 просмотров
Решения вопроса 1
hzzzzl
@hzzzzl
лучше всего через css, но если через реакт, то обновлять стейт при событии onMouseOver/Out, и перерендеривать с новым классом

https://codesandbox.io/s/pensive-dubinsky-e7xt7
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
humiliation
@humiliation
Чем больше знаю - тем больше дурак
<div onMouseOver={(e)=>e.currentTarget.classList.add('o-s')}
     onMouseLeave={(e)=>e.currentTarget.classList.remove('o-s')}
     >
     Hello React..!
</div>

Если стейт не нужен. Можно создать функцию и вынести туда проверку.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы