|
1 |
| -import React from 'react' |
| 1 | +import React, { useRef, useEffect } from 'react' |
2 | 2 | import { createRoot } from 'react-dom/client'
|
3 | 3 | import { createStore } from 'redux'
|
4 | 4 | import { Provider, connect } from 'react-redux'
|
@@ -186,87 +186,63 @@ type Props = {
|
186 | 186 | createChannel: (channel: string) => Action
|
187 | 187 | changeChannel: (channel: string) => Action
|
188 | 188 | }
|
| 189 | +const ChannelView = (props: Props) => { |
| 190 | + const { state, updateMsg, deleteMsg, startEdit, stopEdit } = props |
| 191 | + const { current_channel: ch, editing } = state |
| 192 | + const channel = state.channels[ch] |
189 | 193 |
|
190 |
| -class ChannelView extends React.Component<Props> { |
191 |
| - elem: React.RefObject<HTMLUListElement> |
192 |
| - elemEdit: React.RefObject<HTMLInputElement> |
193 |
| - onSubmit: (e: React.FormEvent) => void |
| 194 | + const elem = useRef<HTMLUListElement>(null) |
| 195 | + const elemEdit = useRef<HTMLInputElement>(null) |
194 | 196 |
|
195 |
| - constructor(props: Props) { |
196 |
| - super(props) |
197 |
| - |
198 |
| - this.elem = React.createRef() |
199 |
| - this.elemEdit = React.createRef() |
200 |
| - |
201 |
| - this.onSubmit = (e) => { |
202 |
| - e.preventDefault() |
203 |
| - |
204 |
| - const node = this.elemEdit.current |
205 |
| - if (node != null) { |
206 |
| - node.blur() |
207 |
| - } |
208 |
| - } |
| 197 | + const onSubmit = (e: React.FormEvent) => { |
| 198 | + e.preventDefault() |
| 199 | + elemEdit.current?.blur() |
209 | 200 | }
|
210 | 201 |
|
211 |
| - componentDidUpdate() { |
212 |
| - const node = this.elem.current |
213 |
| - if (node != null) { |
| 202 | + useEffect(() => { |
| 203 | + if (elem.current != null) { |
214 | 204 | // TODO: 남이 메세지를 보냈을때도 스크롤이 확확 올라가버리면 곤란함
|
215 |
| - node.scrollTop = node.scrollHeight - node.clientHeight |
| 205 | + elem.current.scrollTop = |
| 206 | + elem.current.scrollHeight - elem.current.clientHeight |
216 | 207 | }
|
217 |
| - |
218 |
| - const nodeEdit = this.elemEdit.current |
219 |
| - if (nodeEdit != null) { |
220 |
| - nodeEdit.focus() |
221 |
| - } |
222 |
| - } |
223 |
| - |
224 |
| - render() { |
225 |
| - const p: Props = this.props |
226 |
| - const { current_channel: ch, editing } = p.state |
227 |
| - const channel = p.state.channels[ch] |
228 |
| - |
229 |
| - const lines = [] |
230 |
| - for (const [id, { userid, usernick, txt }] of channel) { |
231 |
| - const is_editable: boolean = userid.localeCompare(myid) === 0 |
232 |
| - const is_editing: boolean = |
233 |
| - editing == null || id.localeCompare(editing) !== 0 |
234 |
| - |
235 |
| - lines.push( |
236 |
| - <li key={id}> |
237 |
| - <span className="nick">{usernick}</span> |
238 |
| - {((_) => |
239 |
| - is_editing ? ( |
240 |
| - <div className="content">{txt}</div> |
241 |
| - ) : ( |
242 |
| - <form className="content" onSubmit={this.onSubmit}> |
243 |
| - <input |
244 |
| - value={txt} |
245 |
| - ref={this.elemEdit} |
246 |
| - onBlur={p.stopEdit} |
247 |
| - onChange={(_) => |
248 |
| - p.updateMsg(ch, this.elemEdit.current!.value, id) |
249 |
| - } |
250 |
| - /> |
251 |
| - </form> |
252 |
| - ))()} |
253 |
| - {((_) => |
254 |
| - !is_editable ? null : ( |
255 |
| - <span className="control"> |
256 |
| - <span onClick={(_) => p.startEdit(id)}> |
257 |
| - <i className="fas fa-pencil-alt" /> |
258 |
| - </span> |
259 |
| - |
260 |
| - <span onClick={(_) => p.deleteMsg(ch, id)}> |
261 |
| - <i className="fas fa-trash" /> |
262 |
| - </span> |
263 |
| - </span> |
264 |
| - ))()} |
265 |
| - </li>, |
266 |
| - ) |
267 |
| - } |
268 |
| - return <ul ref={this.elem}>{lines}</ul> |
269 |
| - } |
| 208 | + elemEdit.current?.focus() |
| 209 | + }) |
| 210 | + |
| 211 | + const lines = Array.from(channel).map(([id, { userid, usernick, txt }]) => { |
| 212 | + const is_editable = userid.localeCompare(myid) === 0 |
| 213 | + const is_editing = editing == null || id.localeCompare(editing) !== 0 |
| 214 | + |
| 215 | + return ( |
| 216 | + <li key={id}> |
| 217 | + <span className="nick">{usernick}</span> |
| 218 | + {is_editing ? ( |
| 219 | + <div className="content">{txt}</div> |
| 220 | + ) : ( |
| 221 | + <form className="content" onSubmit={onSubmit}> |
| 222 | + <input |
| 223 | + value={txt} |
| 224 | + ref={elemEdit} |
| 225 | + onBlur={stopEdit} |
| 226 | + onChange={() => updateMsg(ch, elemEdit.current!.value, id)} |
| 227 | + /> |
| 228 | + </form> |
| 229 | + )} |
| 230 | + {is_editable && ( |
| 231 | + <span className="control"> |
| 232 | + <span onClick={() => startEdit(id)}> |
| 233 | + <i className="fas fa-pencil-alt" /> |
| 234 | + </span> |
| 235 | + |
| 236 | + <span onClick={() => deleteMsg(ch, id)}> |
| 237 | + <i className="fas fa-trash" /> |
| 238 | + </span> |
| 239 | + </span> |
| 240 | + )} |
| 241 | + </li> |
| 242 | + ) |
| 243 | + }) |
| 244 | + |
| 245 | + return <ul ref={elem}>{lines}</ul> |
270 | 246 | }
|
271 | 247 |
|
272 | 248 | const View = (props: Props) => {
|
|
0 commit comments