From d9024ff83722303c8ce6fed039fe3029534b6cf5 Mon Sep 17 00:00:00 2001 From: ekzyis Date: Tue, 3 Sep 2024 16:15:04 +0200 Subject: [PATCH] Reinitialize wallet form if initial values change + fix readOnly hydration error (#1354) * Reinitialize wallet form if initial values change This fixes that enabled is not set on first render if only recv is configured * Remove unnecessary old usage of ClientCheckbox This isn't needed even without enableReinitialize since for send, enabled is correctly set on first render. It was needed in the past when we were still validating wallets before enabling them on first page load but now, we simply load the configuration from localStorage which is immediately available on the client. * Fix readOnly hydration error * Replace repetitive isMounted logic with useIsClient hook --- components/autowithdraw-shared.js | 8 +++----- components/form.js | 3 ++- components/use-client.js | 12 ++++++++++++ pages/settings/wallets/[wallet].js | 13 ++++++++----- pages/settings/wallets/index.js | 14 ++++---------- 5 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 components/use-client.js diff --git a/components/autowithdraw-shared.js b/components/autowithdraw-shared.js index c11d5da8..97b9d6a7 100644 --- a/components/autowithdraw-shared.js +++ b/components/autowithdraw-shared.js @@ -3,6 +3,7 @@ import { Checkbox, Input } from './form' import { useMe } from './me' import { useEffect, useState } from 'react' import { isNumber } from '@/lib/validate' +import { useIsClient } from './use-client' function autoWithdrawThreshold ({ me }) { return isNumber(me?.privates?.autoWithdrawThreshold) ? me?.privates?.autoWithdrawThreshold : 10000 @@ -25,15 +26,12 @@ export function AutowithdrawSettings ({ wallet }) { setSendThreshold(Math.max(Math.floor(threshold / 10), 1)) }, [autoWithdrawThreshold]) - const [mounted, setMounted] = useState(false) - useEffect(() => { - setMounted(true) - }, []) + const isClient = useIsClient() return ( <> { + setClient(true) + }, []) + + return isClient +} diff --git a/pages/settings/wallets/[wallet].js b/pages/settings/wallets/[wallet].js index 2dd86f22..0343893f 100644 --- a/pages/settings/wallets/[wallet].js +++ b/pages/settings/wallets/[wallet].js @@ -1,15 +1,16 @@ import { getGetServerSideProps } from '@/api/ssrApollo' -import { Form, ClientInput, ClientCheckbox, PasswordInput, CheckboxGroup } from '@/components/form' +import { Form, ClientInput, PasswordInput, CheckboxGroup, Checkbox } from '@/components/form' import { CenterLayout } from '@/components/layout' import { WalletSecurityBanner } from '@/components/banners' import { WalletLogs } from '@/components/wallet-logger' import { useToast } from '@/components/toast' import { useRouter } from 'next/router' -import { useWallet, Status } from 'wallets' +import { useWallet } from 'wallets' import Info from '@/components/info' import Text from '@/components/text' import { AutowithdrawSettings } from '@/components/autowithdraw-shared' import dynamic from 'next/dynamic' +import { useIsClient } from '@/components/use-client' const WalletButtonBar = dynamic(() => import('@/components/wallet-buttonbar.js'), { ssr: false }) @@ -45,6 +46,7 @@ export default function WalletSettings () { {wallet.canSend && wallet.hasConfig > 0 && }
{ try { @@ -70,9 +72,8 @@ export default function WalletSettings () { ? : ( - { const rawProps = { ...props, name, initialValue: config?.[name], - readOnly: isConfigured && editable === false && !!config?.[name], + readOnly: isClient && isConfigured && editable === false && !!config?.[name], groupClassName: props.hidden ? 'd-none' : undefined, label: label ? ( diff --git a/pages/settings/wallets/index.js b/pages/settings/wallets/index.js index 3bb77c3e..568018dc 100644 --- a/pages/settings/wallets/index.js +++ b/pages/settings/wallets/index.js @@ -3,8 +3,9 @@ import Layout from '@/components/layout' import styles from '@/styles/wallet.module.css' import Link from 'next/link' import { useWallets, walletPrioritySort } from 'wallets' -import { useEffect, useState } from 'react' +import { useState } from 'react' import dynamic from 'next/dynamic' +import { useIsClient } from '@/components/use-client' const WalletCard = dynamic(() => import('@/components/wallet-card'), { ssr: false }) @@ -29,17 +30,10 @@ async function reorder (wallets, sourceIndex, targetIndex) { export default function Wallet ({ ssrData }) { const { wallets } = useWallets() - const [mounted, setMounted] = useState(false) + const isClient = useIsClient() const [sourceIndex, setSourceIndex] = useState(null) const [targetIndex, setTargetIndex] = useState(null) - useEffect(() => { - // mounted is required since draggable is false - // for wallets only available on the client during SSR - // and thus we need to render the component again on the client - setMounted(true) - }, []) - const onDragStart = (i) => (e) => { // e.dataTransfer.dropEffect = 'move' // We can only use the DataTransfer API inside the drop event @@ -94,7 +88,7 @@ export default function Wallet ({ ssrData }) { return walletPrioritySort(w1, w2) }) .map((w, i) => { - const draggable = mounted && w.enabled + const draggable = isClient && w.enabled return (