From fccc23c05712b0b54e77daefd4b74855e52f08b6 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Mon, 8 Apr 2019 15:42:24 +0300 Subject: App, Chat, Thread using hooks --- vnext/src/App.js | 282 ++++++++++++++++++----------------------- vnext/src/components/Chat.js | 98 +++++++------- vnext/src/components/Thread.js | 12 +- 3 files changed, 180 insertions(+), 212 deletions(-) diff --git a/vnext/src/App.js b/vnext/src/App.js index 7978abe5..6fcf3d9c 100644 --- a/vnext/src/App.js +++ b/vnext/src/App.js @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'; -import * as qs from 'qs'; +import qs from 'qs'; import Icon from './components/Icon'; import { Discover, Discussions, Blog, Tag, Home } from './components/Feeds'; @@ -11,179 +11,149 @@ import Chat from './components/Chat'; import Post from './components/Post'; import Thread from './components/Thread'; import LoginButton from './components/LoginButton'; -import Avatar from './components/Avatar'; import { UserLink } from './components/UserInfo'; import Header from './components/Header'; import SearchBox from './components/SearchBox'; -import NavigationIcon from './components/NavigationIcon'; import cookies from 'react-cookies'; import { me } from './api'; -const app = document.getElementById('app'); - -export default class App extends React.Component { - constructor(props) { - super(props); - let params = qs.parse(window.location.search.substring(1)); - if (params.hash) { - cookies.save('hash', params.hash, { path: '/' }); - window.history.replaceState({}, document.title, `${window.location.protocol}//${window.location.host}${window.location.pathname}`); - } - this.state = { - visitor: { - uid: 0, - hash: cookies.load('hash') - }, - appMarginLeft: 'inherit' - }; - this.pm = React.createRef(); - this.thread = React.createRef(); - this.sidebar = React.createRef(); +export default function App(props) { + let params = qs.parse(window.location.search.substring(1)); + if (params.hash) { + cookies.save('hash', params.hash, { path: '/' }); + window.history.replaceState({}, document.title, `${window.location.protocol}//${window.location.host}${window.location.pathname}`); } + const [visitor, setVisitor] = useState({ + uid: 0, + hash: cookies.load('hash') + }); + + let updateStatus = () => { + // refresh server visitor state (unread counters) + me().then(visitor => { + setVisitor(visitor); + }); + }; - initES = () => { - if (!('EventSource' in window)) { - return; + const [es, setEs] = useState(); + useEffect(() => { + const { hash } = visitor; + if (hash) { + me().then(visitor => auth(visitor)); } - const params = { hash: this.state.visitor.hash }; - let url = new URL(`https://api.juick.com/events?${qs.stringify(params)}`); - this.es = new EventSource(url); - this.es.onopen = () => { + const eventParams = { hash: visitor.hash }; + let url = new URL(`https://api.juick.com/events?${qs.stringify(eventParams)}`); + let es = new EventSource(url); + es.onopen = () => { console.log('online'); + es.addEventListener('read', updateStatus); }; - this.es.addEventListener('msg', msg => { - try { - var jsonMsg = JSON.parse(msg.data); - console.log('data: ' + msg.data); - // refresh server visitor state (unread counters) - me().then(visitor => { - this.setState({ - visitor: visitor - }); - }); - if (jsonMsg.service) { - return; - } - if (!jsonMsg.mid) { - this.pm.current.onMessage(jsonMsg); - } - } catch (err) { - console.log(err); - } - }); - } - - componentDidMount() { - const { hash } = this.state.visitor; - this.initES(); - if (hash) { - me().then(visitor => this.auth(visitor)); + es.onerror = () => { + es.removeEventListener('read', updateStatus); } - } - search = (history, pathname, searchString) => { + setEs(es); + }, []); + + + let search = (history, pathname, searchString) => { let location = {}; location.pathname = pathname; location.search = `?search=${searchString}`; history.push(location); } - render() { - const user = this.state.visitor; - return ( - - <> -
-
- { - user.uid > 0 ? - - : - } - - + let auth = (visitor) => { + setVisitor(visitor); + } + return ( + + <> +
+
+ { + visitor.uid > 0 ? + + : + } + -
-
- - } /> - } /> - - - } /> - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - -
- { - user.uid > 0 && - - } - -
- ); - } - auth = (visitor) => { - this.setState({ - visitor: visitor - }); - } + + {visitor.uid > 0 ? + + + Post + + : + + } + +
+
+
+ + } /> + } /> + + + } /> + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + +
+ { + visitor.uid > 0 && + + } + +
+ ); } diff --git a/vnext/src/components/Chat.js b/vnext/src/components/Chat.js index 57415d29..e2b8d2f1 100644 --- a/vnext/src/components/Chat.js +++ b/vnext/src/components/Chat.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from 'react'; import ReactRouterPropTypes from 'react-router-prop-types'; import { UserType } from './Types'; import moment from 'moment'; @@ -11,74 +11,68 @@ import { getChat, pm } from '../api'; import './Chat.css'; -export default class Chat extends React.Component { - constructor(props) { - super(props); - - this.state = { - chats: [] +export default function Chat(props) { + const [chats, setChats] = useState([]); + useEffect(() => { + console.log(props.connection); + if (props.connection) { + props.connection.addEventListener('msg', onMessage); + } + loadChat(props.match.params.user); + return () => { + if (props.connection) { + props.connection.removeEventListener('msg', onMessage); + } }; - } - componentDidMount() { - this.loadChat(this.props.match.params.user); - } + }, [props.connection]); - loadChat = (uname) => { - const { hash } = this.props.visitor; - this.setState({ - chats: [] - }); + let loadChat = (uname) => { + const { hash } = props.visitor; + setChats([]); if (hash && uname) { getChat(uname) .then(response => { - this.setState({ - chats: response.data - }); + setChats(response.data); }); } } - onMessage = (msg) => { - if (msg.user.uname === this.props.match.params.user) { - this.setState({ - chats: [msg, ...this.state.chats] - }); + let onMessage = (json) => { + const msg = JSON.parse(json.data); + if (msg.user.uname === props.match.params.user) { + setChats([msg, ...chats]); } } - onSend = (template) => { + let onSend = (template) => { pm(template.to.uname, template.body) .then(res => { - this.loadChat(this.props.match.params.user); + loadChat(props.match.params.user); }).catch(console.log); } - - render() { - const { chats } = this.state; - const uname = this.props.match.params.user; - return ( -
- - {uname ? ( -
-
    - { - chats.map((chat) => - - ) - } -
- - Reply... + const uname = props.match.params.user; + return ( +
+ + {uname ? ( +
+
    + { + chats.map((chat) => + + ) + } +
+ + Reply... -
- ) : ( -

No chat selected

- ) - } -
- ); - } +
+ ) : ( +

No chat selected

+ ) + } +
+ ); } Chat.propTypes = { diff --git a/vnext/src/components/Thread.js b/vnext/src/components/Thread.js index d61fd87f..c1dc915b 100644 --- a/vnext/src/components/Thread.js +++ b/vnext/src/components/Thread.js @@ -22,13 +22,17 @@ export default function Thread(props) { const [loading, setLoading] = useState(false); const [active, setActive] = useState(0); useEffect(() => { - props.connection.addEventListener('msg', onReply); + if (props.connection) { + props.connection.addEventListener('msg', onReply); + } setActive(0); loadReplies(); return () => { - props.connection.removeEventListener('msg', onReply); + if (props.connection) { + props.connection.removeEventListener('msg', onReply); + } } - }, []); + }, [props.connection]); let loadReplies = () => { document.body.scrollTop = 0; document.documentElement.scrollTop = 0; @@ -54,7 +58,7 @@ export default function Thread(props) { }); } let onReply = (json) => { - const msg = JSON.parse(json); + const msg = JSON.parse(json.data); if (msg.mid == message.mid) { setReplies([...this.state.replies, msg]); } -- cgit v1.2.3