codeViewer: refactor to use hooks

This commit is contained in:
Peter Cai 2020-02-20 10:56:39 +08:00
parent e3e3445b93
commit 17d6add3dc
No known key found for this signature in database
GPG Key ID: 71F5FB4E4F3FD54F
2 changed files with 63 additions and 46 deletions

View File

@ -1,54 +1,43 @@
import React from "react"
import React, { useState } from "react"
import hljs from "highlight.js"
import * as hooks from "./hooks"
import LinkButton from "./util/linkButton"
MAX_HIGHLIGHT_LENGTH = 10 * 1024 # 10 KiB
class CodeViewer extends React.Component
constructor: (props) ->
super props
@state =
code: "Loading..."
highlight: true
export default CodeViewer = (props) ->
[code, setCode] = useState "Loading..."
[highlight, setHighlight] = useState true
componentDidMount: ->
resp = await fetch "/paste/#{@props.id}?original"
# Fetch the content on first mount (and after first render)
hooks.useFetchContent props.id, (meta, resp) ->
resp = await resp.text()
if resp.length < MAX_HIGHLIGHT_LENGTH
resp = hljs.highlightAuto(resp).value
if meta.length < MAX_HIGHLIGHT_LENGTH
setCode hljs.highlightAuto(resp).value
else
@setState
highlight: false
setHighlight false
setCode resp
@setState
code: resp
render: ->
if @state.switchToHome
return <Redirect push to="/paste/text" />
<div className="content-pastebin">
<div
className="content-code-viewer"
>
{
if @state.highlight
<pre
dangerouslySetInnerHTML={{__html: @state.code}}
/>
else
<pre>{@state.code}</pre>
}
</div>
<div className="content-buttons">
<LinkButton
className="button-blue"
push
to="/paste/text"
>
New Paste
</LinkButton>
</div>
<div className="content-pastebin">
<div
className="content-code-viewer"
>
{
if highlight
<pre
dangerouslySetInnerHTML={{__html: code}}
/>
else
<pre>{code}</pre>
}
</div>
export default CodeViewer
<div className="content-buttons">
<LinkButton
className="button-blue"
push
to="/paste/text"
>
New Paste
</LinkButton>
</div>
</div>

View File

@ -1,4 +1,4 @@
import React, { useState, useCallback } from "react"
import React, { useState, useCallback, useEffect } from "react"
import ReactModal from "react-modal"
# Simple abstraction for a toggling state
@ -90,4 +90,32 @@ export usePaste = (openDialog, callback) ->
useCallback(doPaste, [openDialog, callback]),
pasting,
progress
]
]
# An effect that fetches the original pasted content,
# and then fires a callback that handles metadata and the response body
# it also stores the meta into a state and returns it every time
# this hook gets called, so callbacks are not necessary
# and if callback is not present, then the response body
# would simply be thrown away
export useFetchContent = (id, callback) ->
[meta, setMeta] = useState null
doFetch = ->
resp = await fetch "/paste/#{id}?original"
length = resp.headers.get 'content-length'
mime = resp.headers.get 'content-type'
[_, name] = resp.headers.get 'content-disposition'
.split 'filename*='
newMeta =
name: name
mime: mime
length: length
setMeta newMeta
# We have to pass newMeta to callback because
# the callback will not be aware of the meta update
callback newMeta, resp if callback
# Run the effect once on mount
useEffect doFetch, []
meta