refactor: memoize buttons on export

This commit is contained in:
rusconn
2023-06-24 13:58:57 +09:00
parent 240fba0e74
commit 822a8db8f9
13 changed files with 103 additions and 188 deletions

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useState } from "react";
import yaml from "js-yaml"; import yaml from "js-yaml";
import { toolGroups } from "@/config/tools"; import { toolGroups } from "@/config/tools";
@@ -104,47 +104,30 @@ export default function Page() {
/> />
); );
const jsonPasteButton = useMemo( const jsonPasteButton = <PasteButton onClipboardRead={setJsonReactively} />;
() => <PasteButton onClipboardRead={setJsonReactively} />, const yamlPasteButton = <PasteButton onClipboardRead={setYamlReactively} />;
[setJsonReactively]
);
const yamlPasteButton = useMemo( const jsonFileButton = (
() => <PasteButton onClipboardRead={setYamlReactively} />, <FileButton
[setYamlReactively] accept=".json"
onFileRead={setJsonReactively}
iconOnly
aria-label="load a json file"
/>
); );
const yamlFileButton = (
const jsonFileButton = useMemo( <FileButton
() => ( accept=".yml,.yaml"
<FileButton onFileRead={setYamlReactively}
accept=".json" iconOnly
onFileRead={setJsonReactively} aria-label="load a yaml file"
iconOnly />
aria-label="load a json file"
/>
),
[setJsonReactively]
);
const yamlFileButton = useMemo(
() => (
<FileButton
accept=".yml,.yaml"
onFileRead={setYamlReactively}
iconOnly
aria-label="load a yaml file"
/>
),
[setYamlReactively]
); );
const jsonCopyButton = <CopyButton text={form.json} />; const jsonCopyButton = <CopyButton text={form.json} />;
const yamlCopyButton = <CopyButton text={form.yaml} />; const yamlCopyButton = <CopyButton text={form.yaml} />;
const clearButton = useMemo( const clearButton = <ClearButton onClick={clearBoth} iconOnly aria-label="clear json and yaml" />;
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear json and yaml" />,
[clearBoth]
);
const jsonControl = ( const jsonControl = (
<ControlMenu list={[jsonPasteButton, jsonFileButton, jsonCopyButton, clearButton]} /> <ControlMenu list={[jsonPasteButton, jsonFileButton, jsonCopyButton, clearButton]} />

View File

@@ -77,10 +77,10 @@ export default function Page() {
[format] [format]
); );
const decPasteButton = useMemo(() => <PasteButton onClipboardRead={trySetDec} />, [trySetDec]); const decPasteButton = <PasteButton onClipboardRead={trySetDec} />;
const hexPasteButton = useMemo(() => <PasteButton onClipboardRead={trySetHex} />, [trySetHex]); const hexPasteButton = <PasteButton onClipboardRead={trySetHex} />;
const octPasteButton = useMemo(() => <PasteButton onClipboardRead={trySetOct} />, [trySetOct]); const octPasteButton = <PasteButton onClipboardRead={trySetOct} />;
const binPasteButton = useMemo(() => <PasteButton onClipboardRead={trySetBin} />, [trySetBin]); const binPasteButton = <PasteButton onClipboardRead={trySetBin} />;
const decControl = <ControlMenu list={[decPasteButton]} />; const decControl = <ControlMenu list={[decPasteButton]} />;
const hexControl = <ControlMenu list={[hexPasteButton]} />; const hexControl = <ControlMenu list={[hexPasteButton]} />;

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useState } from "react";
import { decode, encode, isValid } from "js-base64"; import { decode, encode, isValid } from "js-base64";
import { toolGroups } from "@/config/tools"; import { toolGroups } from "@/config/tools";
@@ -48,36 +48,21 @@ export default function Page() {
const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) => const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
setEncodedReactively(value); setEncodedReactively(value);
const decodedPasteButton = useMemo( const decodedPasteButton = <PasteButton onClipboardRead={setDecodedReactively} />;
() => <PasteButton onClipboardRead={setDecodedReactively} />, const encodedPasteButton = <PasteButton onClipboardRead={setEncodedReactively} />;
[setDecodedReactively]
const decodedFileButton = (
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
);
const encodedFileButton = (
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
); );
const encodedPasteButton = useMemo( const decodedCopyButton = <CopyButton text={form.decoded} />;
() => <PasteButton onClipboardRead={setEncodedReactively} />, const encodedCopyButton = <CopyButton text={form.encoded} />;
[setEncodedReactively]
);
const decodedFileButton = useMemo( const clearButton = (
() => ( <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
),
[setDecodedReactively]
);
const encodedFileButton = useMemo(
() => (
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
),
[setEncodedReactively]
);
const decodedCopyButton = useMemo(() => <CopyButton text={form.decoded} />, [form.decoded]);
const encodedCopyButton = useMemo(() => <CopyButton text={form.encoded} />, [form.encoded]);
const clearButton = useMemo(
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
[clearBoth]
); );
const decodedControl = ( const decodedControl = (

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useState } from "react";
import { escape, unescape } from "html-escaper"; import { escape, unescape } from "html-escaper";
import { toolGroups } from "@/config/tools"; import { toolGroups } from "@/config/tools";
@@ -46,36 +46,21 @@ export default function Page() {
const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) => const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
setEncodedReactively(value); setEncodedReactively(value);
const decodedPasteButton = useMemo( const decodedPasteButton = <PasteButton onClipboardRead={setDecodedReactively} />;
() => <PasteButton onClipboardRead={setDecodedReactively} />, const encodedPasteButton = <PasteButton onClipboardRead={setEncodedReactively} />;
[setDecodedReactively]
const decodedFileButton = (
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
);
const encodedFileButton = (
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
); );
const encodedPasteButton = useMemo( const decodedCopyButton = <CopyButton text={form.decoded} />;
() => <PasteButton onClipboardRead={setEncodedReactively} />, const encodedCopyButton = <CopyButton text={form.encoded} />;
[setEncodedReactively]
);
const decodedFileButton = useMemo( const clearButton = (
() => ( <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
),
[setDecodedReactively]
);
const encodedFileButton = useMemo(
() => (
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
),
[setEncodedReactively]
);
const decodedCopyButton = useMemo(() => <CopyButton text={form.decoded} />, [form.decoded]);
const encodedCopyButton = useMemo(() => <CopyButton text={form.encoded} />, [form.encoded]);
const clearButton = useMemo(
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
[clearBoth]
); );
const decodedControl = ( const decodedControl = (

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useState } from "react";
import { toolGroups } from "@/config/tools"; import { toolGroups } from "@/config/tools";
import { decode } from "@/lib/jwt"; import { decode } from "@/lib/jwt";
@@ -27,20 +27,16 @@ export default function Page() {
const onJwtChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) => setJwt(value); const onJwtChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) => setJwt(value);
const jwtTokenPasteButton = useMemo(() => <PasteButton onClipboardRead={setJwt} />, [setJwt]); const jwtTokenPasteButton = <PasteButton onClipboardRead={setJwt} />;
const jwtTokenFileButton = useMemo( const jwtTokenFileButton = (
() => <FileButton onFileRead={setJwt} iconOnly aria-label="load a token file" />, <FileButton onFileRead={setJwt} iconOnly aria-label="load a token file" />
[setJwt]
); );
const jwtTokenClearButton = useMemo( const jwtTokenClearButton = <ClearButton onClick={clearJwt} iconOnly aria-label="clear token" />;
() => <ClearButton onClick={clearJwt} iconOnly aria-label="clear token" />,
[clearJwt]
);
const heaederCopyButton = useMemo(() => <CopyButton text={header} />, [header]); const heaederCopyButton = <CopyButton text={header} />;
const payloadCopyButton = useMemo(() => <CopyButton text={payload} />, [payload]); const payloadCopyButton = <CopyButton text={payload} />;
const jwtTokenControl = ( const jwtTokenControl = (
<ControlMenu list={[jwtTokenPasteButton, jwtTokenFileButton, jwtTokenClearButton]} /> <ControlMenu list={[jwtTokenPasteButton, jwtTokenFileButton, jwtTokenClearButton]} />

View File

@@ -1,6 +1,6 @@
"use client"; "use client";
import { useCallback, useMemo, useState } from "react"; import { useCallback, useState } from "react";
import { toolGroups } from "@/config/tools"; import { toolGroups } from "@/config/tools";
import { safeDecodeURIComponent, safeEncodeURIComponent } from "@/lib/uri"; import { safeDecodeURIComponent, safeEncodeURIComponent } from "@/lib/uri";
@@ -46,36 +46,21 @@ export default function Page() {
const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) => const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
setEncodedReactively(value); setEncodedReactively(value);
const decodedPasteButton = useMemo( const decodedPasteButton = <PasteButton onClipboardRead={setDecodedReactively} />;
() => <PasteButton onClipboardRead={setDecodedReactively} />, const encodedPasteButton = <PasteButton onClipboardRead={setEncodedReactively} />;
[setDecodedReactively]
const decodedFileButton = (
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
);
const encodedFileButton = (
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
); );
const encodedPasteButton = useMemo( const decodedCopyButton = <CopyButton text={form.decoded} />;
() => <PasteButton onClipboardRead={setEncodedReactively} />, const encodedCopyButton = <CopyButton text={form.encoded} />;
[setEncodedReactively]
);
const decodedFileButton = useMemo( const clearButton = (
() => ( <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
),
[setDecodedReactively]
);
const encodedFileButton = useMemo(
() => (
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
),
[setEncodedReactively]
);
const decodedCopyButton = useMemo(() => <CopyButton text={form.decoded} />, [form.decoded]);
const encodedCopyButton = useMemo(() => <CopyButton text={form.encoded} />, [form.encoded]);
const clearButton = useMemo(
() => <ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />,
[clearBoth]
); );
const decodedControl = ( const decodedControl = (

View File

@@ -67,21 +67,15 @@ export default function Page() {
[indentation] [indentation]
); );
const inputPasteButton = useMemo(() => <PasteButton onClipboardRead={setInput} />, []); const inputPasteButton = <PasteButton onClipboardRead={setInput} />;
const inputFileButton = useMemo( const inputFileButton = (
() => ( <FileButton accept=".json" onFileRead={setInput} iconOnly aria-label="load a json file" />
<FileButton accept=".json" onFileRead={setInput} iconOnly aria-label="load a json file" />
),
[]
); );
const inputClearButton = useMemo( const inputClearButton = <ClearButton onClick={clearInput} iconOnly aria-label="clear json" />;
() => <ClearButton onClick={clearInput} iconOnly aria-label="clear json" />,
[clearInput]
);
const outputCopyButton = useMemo(() => <CopyButton text={output} />, [output]); const outputCopyButton = <CopyButton text={output} />;
const inputControl = <ControlMenu list={[inputPasteButton, inputFileButton, inputClearButton]} />; const inputControl = <ControlMenu list={[inputPasteButton, inputFileButton, inputClearButton]} />;
const outputControl = <ControlMenu list={[outputCopyButton]} />; const outputControl = <ControlMenu list={[outputCopyButton]} />;

View File

@@ -56,39 +56,16 @@ export default function Page() {
[uppercase] [uppercase]
); );
const inputPasteButton = useMemo(() => <PasteButton onClipboardRead={setInput} />, []); const inputPasteButton = <PasteButton onClipboardRead={setInput} />;
const inputFileButton = <FileButton onFileRead={setInput} iconOnly aria-label="load a file" />;
const inputFileButton = useMemo( const inputClearButton = <ClearButton onClick={clearInput} iconOnly aria-label="clear input" />;
() => <FileButton onFileRead={setInput} iconOnly aria-label="load a file" />,
[]
);
const inputClearButton = useMemo(
() => <ClearButton onClick={clearInput} iconOnly aria-label="clear input" />,
[clearInput]
);
const inputControl = <ControlMenu list={[inputPasteButton, inputFileButton, inputClearButton]} />; const inputControl = <ControlMenu list={[inputPasteButton, inputFileButton, inputClearButton]} />;
const md5CopyButton = useMemo( const md5CopyButton = <CopyButton text={md5} iconOnly aria-label="copy generated md5" />;
() => <CopyButton text={md5} iconOnly aria-label="copy generated md5" />, const sha1CopyButton = <CopyButton text={sha1} iconOnly aria-label="copy generated sha1" />;
[md5] const sha256CopyButton = <CopyButton text={sha256} iconOnly aria-label="copy generated sha256" />;
); const sha512CopyButton = <CopyButton text={sha512} iconOnly aria-label="copy generated sha512" />;
const sha1CopyButton = useMemo(
() => <CopyButton text={sha1} iconOnly aria-label="copy generated sha1" />,
[sha1]
);
const sha256CopyButton = useMemo(
() => <CopyButton text={sha256} iconOnly aria-label="copy generated sha256" />,
[sha256]
);
const sha512CopyButton = useMemo(
() => <CopyButton text={sha512} iconOnly aria-label="copy generated sha512" />,
[sha512]
);
return ( return (
<PageRootSection title={toolGroups.generators.tools.hash.longTitle}> <PageRootSection title={toolGroups.generators.tools.hash.longTitle}>

View File

@@ -142,12 +142,8 @@ export default function Page() {
[generates] [generates]
); );
const uuidsCopyButton = useMemo(() => <CopyButton text={uuidsString} />, [uuidsString]); const uuidsCopyButton = <CopyButton text={uuidsString} />;
const uuidsClearButton = <ClearButton onClick={clearUuids} iconOnly aria-label="clear uuids" />;
const uuidsClearButton = useMemo(
() => <ClearButton onClick={clearUuids} iconOnly aria-label="clear uuids" />,
[clearUuids]
);
const uuidsControl = <ControlMenu list={[uuidsCopyButton, uuidsClearButton]} />; const uuidsControl = <ControlMenu list={[uuidsCopyButton, uuidsClearButton]} />;

View File

@@ -1,9 +1,14 @@
import { memo } from "react";
import equal from "react-fast-compare";
import { icons } from "@/components/icons"; import { icons } from "@/components/icons";
import { BaseButton, BaseButtonProps } from "./base"; import { BaseButton, BaseButtonProps } from "./base";
export type ClearButtonProps = Omit<BaseButtonProps, "icon" | "labelText">; export type ClearButtonProps = Omit<BaseButtonProps, "icon" | "labelText">;
export function ClearButton({ iconOnly, ...props }: ClearButtonProps) { function RawClearButton({ iconOnly, ...props }: ClearButtonProps) {
return <BaseButton {...props} icon={<icons.X size={16} />} {...{ iconOnly }} labelText="Clear" />; return <BaseButton {...props} icon={<icons.X size={16} />} {...{ iconOnly }} labelText="Clear" />;
} }
export const ClearButton = memo(RawClearButton, equal);

View File

@@ -1,4 +1,5 @@
import { useCallback } from "react"; import { memo, useCallback } from "react";
import equal from "react-fast-compare";
import { icons } from "@/components/icons"; import { icons } from "@/components/icons";
@@ -8,7 +9,7 @@ export type CopyButtonProps = Omit<BaseButtonProps, "icon" | "labelText" | "onCl
text: string; text: string;
}; };
export function CopyButton({ text, iconOnly, ...props }: CopyButtonProps) { function RawCopyButton({ text, iconOnly, ...props }: CopyButtonProps) {
const onClick: BaseButtonProps["onClick"] = useCallback(() => { const onClick: BaseButtonProps["onClick"] = useCallback(() => {
navigator.clipboard.writeText(text).catch(e => { navigator.clipboard.writeText(text).catch(e => {
if (e instanceof Error) { if (e instanceof Error) {
@@ -27,3 +28,5 @@ export function CopyButton({ text, iconOnly, ...props }: CopyButtonProps) {
/> />
); );
} }
export const CopyButton = memo(RawCopyButton, equal);

View File

@@ -1,4 +1,5 @@
import { useCallback, useRef } from "react"; import { memo, useCallback, useRef } from "react";
import equal from "react-fast-compare";
import { icons } from "@/components/icons"; import { icons } from "@/components/icons";
@@ -12,7 +13,7 @@ export type FileButtonProps = Pick<InputProps, "accept"> &
onFileRead: (text: string) => void; onFileRead: (text: string) => void;
}; };
export function FileButton({ export function RawFileButton({
accept, accept,
iconOnly, iconOnly,
maxFileSizeMb = 20, maxFileSizeMb = 20,
@@ -67,3 +68,5 @@ export function FileButton({
</> </>
); );
} }
export const FileButton = memo(RawFileButton, equal);

View File

@@ -1,4 +1,5 @@
import { useCallback } from "react"; import { memo, useCallback } from "react";
import equal from "react-fast-compare";
import { icons } from "@/components/icons"; import { icons } from "@/components/icons";
@@ -8,7 +9,7 @@ export type PasteButtonProps = Omit<BaseButtonProps, "icon" | "labelText" | "onC
onClipboardRead: (text: string) => void; onClipboardRead: (text: string) => void;
}; };
export function PasteButton({ iconOnly, onClipboardRead, ...props }: PasteButtonProps) { export function RawPasteButton({ iconOnly, onClipboardRead, ...props }: PasteButtonProps) {
const onClick: BaseButtonProps["onClick"] = useCallback(() => { const onClick: BaseButtonProps["onClick"] = useCallback(() => {
navigator.clipboard navigator.clipboard
.readText() .readText()
@@ -30,3 +31,5 @@ export function PasteButton({ iconOnly, onClipboardRead, ...props }: PasteButton
/> />
); );
} }
export const PasteButton = memo(RawPasteButton, equal);