1717////////////////////////////////////////////////////////////////////////////////
1818import "./styles.css" ;
1919
20- import React from "react" ;
20+ import React , { useState , useEffect , useRef } from "react" ;
2121import ReactDOM from "react-dom" ;
2222import { login , sendMessage , subscribeToMessages } from "./utils" ;
2323
@@ -44,59 +44,43 @@ unsubscribe() // stop listening for new messages
4444The world is your oyster!
4545*/
4646
47- class SmartScroller extends React . Component {
48- autoScroll = true ;
47+ function SmartScroller ( props ) {
48+ const autoScroll = useRef ( true ) ;
49+ const nodeRef = useRef ( ) ;
4950
50- componentDidMount ( ) {
51- this . scrollToBottom ( ) ;
51+ function scrollToBottom ( ) {
52+ if ( autoScroll . current ) {
53+ nodeRef . current . scrollTop = nodeRef . current . scrollHeight ;
54+ }
5255 }
5356
54- componentDidUpdate ( ) {
55- if ( this . autoScroll ) this . scrollToBottom ( ) ;
57+ function handleScroll ( ) {
58+ const { scrollTop, scrollHeight, clientHeight } = nodeRef . current ;
59+ const distanceToBottom = scrollHeight - ( scrollTop + clientHeight ) ;
60+ autoScroll . current = distanceToBottom < 10 ;
5661 }
5762
58- scrollToBottom ( ) {
59- this . node . scrollTop = this . node . scrollHeight ;
60- }
63+ useEffect ( scrollToBottom ) ;
6164
62- handleScroll = ( ) => {
63- const { scrollTop, scrollHeight, clientHeight } = this . node ;
64- const distanceToBottom = scrollHeight - ( scrollTop + clientHeight ) ;
65- this . autoScroll = distanceToBottom < 10 ;
66- } ;
67-
68- render ( ) {
69- return (
70- < div
71- { ...this . props }
72- ref = { node => ( this . node = node ) }
73- onScroll = { this . handleScroll }
74- />
75- ) ;
76- }
65+ return < div { ...props } ref = { nodeRef } onScroll = { handleScroll } /> ;
7766}
7867
79- class Chat extends React . Component {
80- state = {
81- user : null ,
82- messages : [ ]
83- } ;
68+ function Chat ( ) {
69+ const [ user , setUser ] = useState ( null ) ;
70+ const [ messages , setMessages ] = useState ( [ ] ) ;
71+ const inputRef = useRef ( ) ;
8472
85- componentDidMount ( ) {
73+ useEffect ( ( ) => {
8674 login ( user => {
87- this . setState ( { user } ) ;
88-
89- subscribeToMessages ( messages => {
90- this . setState ( { messages } ) ;
91- } ) ;
75+ setUser ( user ) ;
76+ subscribeToMessages ( setMessages ) ;
9277 } ) ;
93- }
78+ } , [ ] ) ;
9479
95- handleSubmit = event => {
80+ function handleSubmit ( event ) {
9681 event . preventDefault ( ) ;
9782
98- const { user } = this . state ;
99- const messageText = this . messageInput . value ;
83+ const messageText = inputRef . current . value ;
10084
10185 sendMessage ( {
10286 userId : user . id ,
@@ -106,64 +90,60 @@ class Chat extends React.Component {
10690
10791 // Clear the form.
10892 event . target . reset ( ) ;
109- } ;
110-
111- render ( ) {
112- const { user, messages } = this . state ;
113-
114- if ( user == null ) return < p > Loading...</ p > ;
115-
116- // Array of arrays of messages grouped by user.
117- const messageGroups = messages . reduce ( ( groups , message ) => {
118- const prevGroup = groups . length && groups [ groups . length - 1 ] ;
119-
120- if ( prevGroup && prevGroup [ 0 ] . userId === message . userId ) {
121- prevGroup . push ( message ) ;
122- } else {
123- groups . push ( [ message ] ) ;
124- }
125-
126- return groups ;
127- } , [ ] ) ;
128-
129- return (
130- < div className = "chat" >
131- < header className = "chat-header" >
132- < h1 className = "chat-title" > HipReact</ h1 >
133- < p className = "chat-message-count" >
134- # messages: { messages . length }
135- </ p >
136- </ header >
137- < SmartScroller className = "messages" >
138- < ol className = "message-groups" >
139- { messageGroups . map ( group => (
140- < li key = { group [ 0 ] . id } className = "message-group" >
141- < div className = "message-group-avatar" >
142- < img src = { group [ 0 ] . photoURL } />
143- </ div >
144- < ol className = "messages" >
145- { group . map ( message => (
146- < li key = { message . id } className = "message" >
147- { message . text }
148- </ li >
149- ) ) }
150- </ ol >
151- </ li >
152- ) ) }
153- </ ol >
154- </ SmartScroller >
155- < form className = "new-message-form" onSubmit = { this . handleSubmit } >
156- < div className = "new-message" >
157- < input
158- ref = { node => ( this . messageInput = node ) }
159- type = "text"
160- placeholder = "say something..."
161- />
162- </ div >
163- </ form >
164- </ div >
165- ) ;
16693 }
94+
95+ if ( user == null ) return < p > Loading...</ p > ;
96+
97+ // Array of arrays of messages grouped by user.
98+ const messageGroups = messages . reduce ( ( groups , message ) => {
99+ const prevGroup = groups . length && groups [ groups . length - 1 ] ;
100+
101+ if ( prevGroup && prevGroup [ 0 ] . userId === message . userId ) {
102+ prevGroup . push ( message ) ;
103+ } else {
104+ groups . push ( [ message ] ) ;
105+ }
106+
107+ return groups ;
108+ } , [ ] ) ;
109+
110+ return (
111+ < div className = "chat" >
112+ < header className = "chat-header" >
113+ < h1 className = "chat-title" > HipReact</ h1 >
114+ < p className = "chat-message-count" >
115+ # messages: { messages . length }
116+ </ p >
117+ </ header >
118+ < SmartScroller className = "messages" >
119+ < ol className = "message-groups" >
120+ { messageGroups . map ( group => (
121+ < li key = { group [ 0 ] . id } className = "message-group" >
122+ < div className = "message-group-avatar" >
123+ < img src = { group [ 0 ] . photoURL } />
124+ </ div >
125+ < ol className = "messages" >
126+ { group . map ( message => (
127+ < li key = { message . id } className = "message" >
128+ { message . text }
129+ </ li >
130+ ) ) }
131+ </ ol >
132+ </ li >
133+ ) ) }
134+ </ ol >
135+ </ SmartScroller >
136+ < form className = "new-message-form" onSubmit = { handleSubmit } >
137+ < div className = "new-message" >
138+ < input
139+ ref = { inputRef }
140+ type = "text"
141+ placeholder = "say something..."
142+ />
143+ </ div >
144+ </ form >
145+ </ div >
146+ ) ;
167147}
168148
169149ReactDOM . render ( < Chat /> , document . getElementById ( "app" ) ) ;
0 commit comments