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

View file

@ -1,4 +1,4 @@
import React, { useState, useCallback } from "react" import React, { useState, useCallback, useEffect } from "react"
import ReactModal from "react-modal" import ReactModal from "react-modal"
# Simple abstraction for a toggling state # Simple abstraction for a toggling state
@ -91,3 +91,31 @@ export usePaste = (openDialog, callback) ->
pasting, pasting,
progress 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