mirror of
https://github.com/EnixCoda/Gitako.git
synced 2026-03-11 08:54:44 +00:00
chore: update IO field names
This commit is contained in:
parent
4be1d2d44d
commit
8f675f5c5b
16 changed files with 88 additions and 93 deletions
|
|
@ -32,7 +32,7 @@ const RawFileExplorer: React.FC<Props & ConnectorState> = function RawFileExplor
|
|||
treeRoot,
|
||||
defer,
|
||||
} = props
|
||||
const { val: config } = useConfigs()
|
||||
const { value: config } = useConfigs()
|
||||
|
||||
React.useEffect(() => {
|
||||
if (treeRoot) {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ const NodeItemIcon = React.memo(function NodeItemIcon({
|
|||
loading?: boolean
|
||||
}) {
|
||||
const {
|
||||
val: { icons },
|
||||
value: { icons },
|
||||
} = useConfigs()
|
||||
|
||||
const src = React.useMemo(
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export function Resizable({ baseSize, className, children }: React.PropsWithChil
|
|||
}, [width, size])
|
||||
|
||||
useCSSVariable('--gitako-width', `${size}px`)
|
||||
useDebounce(() => configContext.set({ sideBarWidth: size }), 100, [size])
|
||||
useDebounce(() => configContext.onChange({ sideBarWidth: size }), 100, [size])
|
||||
|
||||
const onResize = React.useCallback((size: number) => {
|
||||
// do NOT merge this with the above similar effect, side bar will jump otherwise
|
||||
|
|
|
|||
|
|
@ -38,16 +38,16 @@ const RawGitako: React.FC<Props & ConnectorState> = function RawGitako(props) {
|
|||
configContext,
|
||||
} = props
|
||||
|
||||
const accessToken = configContext.val.accessToken || ''
|
||||
const [baseSize] = React.useState(() => configContext.val.sideBarWidth)
|
||||
const accessToken = configContext.value.accessToken || ''
|
||||
const [baseSize] = React.useState(() => configContext.value.sideBarWidth)
|
||||
|
||||
useShrinkGitHubHeader(configContext.val.shrinkGitHubHeader)
|
||||
useShrinkGitHubHeader(configContext.value.shrinkGitHubHeader)
|
||||
|
||||
React.useEffect(() => {
|
||||
run(async function () {
|
||||
if (!accessToken) {
|
||||
const accessToken = await trySetUpAccessTokenWithCode()
|
||||
if (accessToken) configContext.set({ accessToken })
|
||||
if (accessToken) configContext.onChange({ accessToken })
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
|
@ -58,21 +58,21 @@ const RawGitako: React.FC<Props & ConnectorState> = function RawGitako(props) {
|
|||
|
||||
React.useEffect(
|
||||
function attachKeyDown() {
|
||||
if (props.disabled || !configContext.val.shortcut) return
|
||||
if (props.disabled || !configContext.value.shortcut) return
|
||||
|
||||
function onKeyDown(e: KeyboardEvent) {
|
||||
const keys = keyHelper.parseEvent(e)
|
||||
if (keys === configContext.val.shortcut) {
|
||||
if (keys === configContext.value.shortcut) {
|
||||
toggleShowSideBar()
|
||||
}
|
||||
}
|
||||
window.addEventListener('keydown', onKeyDown)
|
||||
return () => window.removeEventListener('keydown', onKeyDown)
|
||||
},
|
||||
[toggleShowSideBar, props.disabled, configContext.val.shortcut],
|
||||
[toggleShowSideBar, props.disabled, configContext.value.shortcut],
|
||||
)
|
||||
|
||||
const intelligentToggle = configContext.val.intelligentToggle
|
||||
const intelligentToggle = configContext.value.intelligentToggle
|
||||
React.useEffect(() => {
|
||||
const shouldShow = intelligentToggle === null ? platform.shouldShow() : intelligentToggle
|
||||
props.setShouldShow(shouldShow)
|
||||
|
|
@ -88,8 +88,8 @@ const RawGitako: React.FC<Props & ConnectorState> = function RawGitako(props) {
|
|||
)
|
||||
useOnPJAXDone(updateSideBarVisibility)
|
||||
|
||||
useGitHubAttachCopyFileButton(configContext.val.copyFileButton)
|
||||
useGitHubAttachCopySnippetButton(configContext.val.copySnippetButton)
|
||||
useGitHubAttachCopyFileButton(configContext.value.copyFileButton)
|
||||
useGitHubAttachCopySnippetButton(configContext.value.copySnippetButton)
|
||||
|
||||
usePJAX()
|
||||
useProgressBar()
|
||||
|
|
@ -122,7 +122,7 @@ const RawGitako: React.FC<Props & ConnectorState> = function RawGitako(props) {
|
|||
freeze={showSettings}
|
||||
accessToken={accessToken}
|
||||
loadWithPJAX={loadWithPJAX}
|
||||
config={configContext.val}
|
||||
config={configContext.value}
|
||||
defer={defer}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ type Props = {
|
|||
export function SimpleToggleField({ field, onChange }: Props) {
|
||||
const { overwrite } = field
|
||||
const configContext = useConfigs()
|
||||
const value = configContext.val[field.key]
|
||||
const value = configContext.value[field.key]
|
||||
return (
|
||||
<Field
|
||||
id={field.key}
|
||||
|
|
@ -57,7 +57,7 @@ export function SimpleToggleField({ field, onChange }: Props) {
|
|||
type={'checkbox'}
|
||||
onChange={async e => {
|
||||
const enabled = e.currentTarget.checked
|
||||
configContext.set({ [field.key]: overwrite ? overwrite.onChange(enabled) : enabled })
|
||||
configContext.onChange({ [field.key]: overwrite ? overwrite.onChange(enabled) : enabled })
|
||||
if (onChange) onChange()
|
||||
}}
|
||||
checked={overwrite ? overwrite.value(value) : Boolean(value)}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ type Props = {
|
|||
export function ToggleShowButton({ error, onClick }: Props) {
|
||||
const ref = React.useRef<HTMLDivElement>(null)
|
||||
const config = useConfigs()
|
||||
const [distance, setDistance] = React.useState(config.val.toggleButtonVerticalDistance)
|
||||
const [distance, setDistance] = React.useState(config.value.toggleButtonVerticalDistance)
|
||||
const { height } = useWindowSize()
|
||||
const buttonHeight = 42
|
||||
React.useEffect(() => {
|
||||
|
|
@ -28,12 +28,12 @@ export function ToggleShowButton({ error, onClick }: Props) {
|
|||
|
||||
// updating context
|
||||
useDebounce(
|
||||
() => config.set({ toggleButtonVerticalDistance: distance }), // too slow
|
||||
() => config.onChange({ toggleButtonVerticalDistance: distance }), // too slow
|
||||
100,
|
||||
[distance],
|
||||
)
|
||||
|
||||
const toggleIconMode = config.val.toggleButtonContent
|
||||
const toggleIconMode = config.value.toggleButtonContent
|
||||
return (
|
||||
<div ref={ref} className={'gitako-toggle-show-button-wrapper'}>
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { platform } from 'platforms'
|
|||
import { Gitea } from 'platforms/Gitea'
|
||||
import { Gitee } from 'platforms/Gitee'
|
||||
import * as React from 'react'
|
||||
import { useStates } from 'utils/hooks/useStates'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
import { SettingsSection } from './SettingsSection'
|
||||
|
||||
const ACCESS_TOKEN_REGEXP = /^[0-9a-f]+$/
|
||||
|
|
@ -14,23 +14,23 @@ type Props = {}
|
|||
|
||||
export function AccessTokenSettings(props: React.PropsWithChildren<Props>) {
|
||||
const configContext = useConfigs()
|
||||
const hasAccessToken = Boolean(configContext.val.accessToken)
|
||||
const useAccessToken = useStates('')
|
||||
const useAccessTokenHint = useStates<React.ReactNode>('')
|
||||
const focusInput = useStates(false)
|
||||
const hasAccessToken = Boolean(configContext.value.accessToken)
|
||||
const useAccessToken = useStateIO('')
|
||||
const useAccessTokenHint = useStateIO<React.ReactNode>('')
|
||||
const focusInput = useStateIO(false)
|
||||
|
||||
const { val: accessTokenHint } = useAccessTokenHint
|
||||
const { val: accessToken } = useAccessToken
|
||||
const { value: accessTokenHint } = useAccessTokenHint
|
||||
const { value: accessToken } = useAccessToken
|
||||
|
||||
React.useEffect(() => {
|
||||
// clear input when access token updates
|
||||
useAccessToken.set('')
|
||||
}, [configContext.val.accessToken])
|
||||
useAccessToken.onChange('')
|
||||
}, [configContext.value.accessToken])
|
||||
|
||||
const onInputAccessToken = React.useCallback(
|
||||
({ currentTarget: { value } }: React.FormEvent<HTMLInputElement>) => {
|
||||
useAccessToken.set(value)
|
||||
useAccessTokenHint.set(
|
||||
useAccessToken.onChange(value)
|
||||
useAccessTokenHint.onChange(
|
||||
ACCESS_TOKEN_REGEXP.test(value) ? '' : 'Gitako does not recognize the token.',
|
||||
)
|
||||
},
|
||||
|
|
@ -42,11 +42,11 @@ export function AccessTokenSettings(props: React.PropsWithChildren<Props>) {
|
|||
}, [])
|
||||
|
||||
const saveToken = React.useCallback(
|
||||
async (hint?: typeof useAccessTokenHint.val) => {
|
||||
async (hint?: typeof useAccessTokenHint.value) => {
|
||||
if (accessToken) {
|
||||
configContext.set({ accessToken })
|
||||
useAccessToken.set('')
|
||||
useAccessTokenHint.set(
|
||||
configContext.onChange({ accessToken })
|
||||
useAccessToken.onChange('')
|
||||
useAccessTokenHint.onChange(
|
||||
hint || (
|
||||
<span>
|
||||
<a href="#" onClick={() => window.location.reload()}>
|
||||
|
|
@ -79,7 +79,7 @@ export function AccessTokenSettings(props: React.PropsWithChildren<Props>) {
|
|||
{hasAccessToken ? (
|
||||
<div>
|
||||
<Text as="p">Your token has been saved.</Text>
|
||||
<Button onClick={() => configContext.set({ accessToken: '' })}>Clear</Button>
|
||||
<Button onClick={() => configContext.onChange({ accessToken: '' })}>Clear</Button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
|
|
@ -110,8 +110,8 @@ export function AccessTokenSettings(props: React.PropsWithChildren<Props>) {
|
|||
className={'access-token-input'}
|
||||
value={accessToken}
|
||||
placeholder="Or input here manually"
|
||||
onFocus={() => focusInput.set(true)}
|
||||
onBlur={() => focusInput.set(false)}
|
||||
onFocus={() => focusInput.onChange(true)}
|
||||
onBlur={() => focusInput.onChange(false)}
|
||||
onChange={onInputAccessToken}
|
||||
onKeyPress={onPressAccessToken}
|
||||
/>
|
||||
|
|
@ -121,7 +121,7 @@ export function AccessTokenSettings(props: React.PropsWithChildren<Props>) {
|
|||
</div>
|
||||
</div>
|
||||
)}
|
||||
{accessTokenHint && !focusInput.val && <span className={'hint'}>{accessTokenHint}</span>}
|
||||
{accessTokenHint && !focusInput.value && <span className={'hint'}>{accessTokenHint}</span>}
|
||||
</SettingsSection>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ export function FileTreeSettings(props: React.PropsWithChildren<Props>) {
|
|||
id="recursive-toggle-folder"
|
||||
options={recursiveToggleFolderOptions}
|
||||
onChange={v => {
|
||||
configContext.set({
|
||||
configContext.onChange({
|
||||
recursiveToggleFolder: v,
|
||||
})
|
||||
}}
|
||||
value={configContext.val.recursiveToggleFolder}
|
||||
value={configContext.value.recursiveToggleFolder}
|
||||
></SelectInput>
|
||||
</Field>
|
||||
<Field title="Icons" id="file-tree-icons">
|
||||
|
|
@ -61,11 +61,11 @@ export function FileTreeSettings(props: React.PropsWithChildren<Props>) {
|
|||
id="file-tree-icons"
|
||||
options={iconOptions}
|
||||
onChange={v => {
|
||||
configContext.set({
|
||||
configContext.onChange({
|
||||
icons: v,
|
||||
})
|
||||
}}
|
||||
value={configContext.val.icons}
|
||||
value={configContext.value.icons}
|
||||
/>
|
||||
</Field>
|
||||
<SimpleToggleField
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { VERSION } from 'env'
|
|||
import { platform } from 'platforms'
|
||||
import { GitHub } from 'platforms/GitHub'
|
||||
import * as React from 'react'
|
||||
import { useStates } from 'utils/hooks/useStates'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
import { SimpleField, SimpleToggleField } from '../SimpleToggleField'
|
||||
import { AccessTokenSettings } from './AccessTokenSettings'
|
||||
import { FileTreeSettings } from './FileTreeSettings'
|
||||
|
|
@ -27,8 +27,8 @@ type Props = {
|
|||
}
|
||||
|
||||
function SettingsBarContent() {
|
||||
const useReloadHint = useStates<React.ReactNode>('')
|
||||
const { val: reloadHint } = useReloadHint
|
||||
const useReloadHint = useStateIO<React.ReactNode>('')
|
||||
const { value: reloadHint } = useReloadHint
|
||||
|
||||
const moreFields: SimpleField[] =
|
||||
platform === GitHub
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { useConfigs } from 'containers/ConfigsContext'
|
|||
import * as React from 'react'
|
||||
import { Config } from 'utils/configHelper'
|
||||
import { friendlyFormatShortcut } from 'utils/general'
|
||||
import { useStates } from 'utils/hooks/useStates'
|
||||
import { useStateIO } from 'utils/hooks/useStateIO'
|
||||
import * as keyHelper from 'utils/keyHelper'
|
||||
import { Field } from './Field'
|
||||
import { SettingsSection } from './SettingsSection'
|
||||
|
|
@ -27,13 +27,13 @@ const toggleButtonContentOptions: Option<Config['toggleButtonContent']>[] = [
|
|||
|
||||
export function SidebarSettings(props: React.PropsWithChildren<Props>) {
|
||||
const configContext = useConfigs()
|
||||
const useToggleShowSideBarShortcut = useStates(configContext.val.shortcut)
|
||||
const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
|
||||
const focused = useStates(false)
|
||||
const useToggleShowSideBarShortcut = useStateIO(configContext.value.shortcut)
|
||||
const { value: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
|
||||
const focused = useStateIO(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
useToggleShowSideBarShortcut.set(configContext.val.shortcut)
|
||||
}, [configContext.val.shortcut])
|
||||
useToggleShowSideBarShortcut.onChange(configContext.value.shortcut)
|
||||
}, [configContext.value.shortcut])
|
||||
|
||||
return (
|
||||
<SettingsSection title={'Sidebar'}>
|
||||
|
|
@ -43,24 +43,24 @@ export function SidebarSettings(props: React.PropsWithChildren<Props>) {
|
|||
id="toggle-sidebar-shortcut"
|
||||
marginRight={1}
|
||||
className={'toggle-shortcut-input'}
|
||||
onFocus={() => focused.set(true)}
|
||||
onBlur={() => focused.set(false)}
|
||||
placeholder={focused.val ? 'Press key combination' : 'Click here to set'}
|
||||
onFocus={() => focused.onChange(true)}
|
||||
onBlur={() => focused.onChange(false)}
|
||||
placeholder={focused.value ? 'Press key combination' : 'Click here to set'}
|
||||
value={friendlyFormatShortcut(toggleShowSideBarShortcut)}
|
||||
onKeyDown={React.useCallback((e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
// Clear shortcut with backspace
|
||||
const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e)
|
||||
useToggleShowSideBarShortcut.set(shortcut)
|
||||
useToggleShowSideBarShortcut.onChange(shortcut)
|
||||
}, [])}
|
||||
readOnly
|
||||
/>
|
||||
{configContext.val.shortcut === toggleShowSideBarShortcut ? (
|
||||
{configContext.value.shortcut === toggleShowSideBarShortcut ? (
|
||||
<Button
|
||||
disabled={!configContext.val.shortcut}
|
||||
disabled={!configContext.value.shortcut}
|
||||
onClick={() => {
|
||||
configContext.set({ shortcut: '' })
|
||||
configContext.onChange({ shortcut: '' })
|
||||
}}
|
||||
>
|
||||
Clear
|
||||
|
|
@ -68,9 +68,9 @@ export function SidebarSettings(props: React.PropsWithChildren<Props>) {
|
|||
) : (
|
||||
<Button
|
||||
onClick={() => {
|
||||
const { val: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
|
||||
const { value: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
|
||||
if (typeof toggleShowSideBarShortcut !== 'string') return
|
||||
configContext.set({ shortcut: toggleShowSideBarShortcut })
|
||||
configContext.onChange({ shortcut: toggleShowSideBarShortcut })
|
||||
}}
|
||||
>
|
||||
Save
|
||||
|
|
@ -83,11 +83,11 @@ export function SidebarSettings(props: React.PropsWithChildren<Props>) {
|
|||
id="toggle-button-content"
|
||||
options={toggleButtonContentOptions}
|
||||
onChange={v => {
|
||||
configContext.set({
|
||||
configContext.onChange({
|
||||
toggleButtonContent: v,
|
||||
})
|
||||
}}
|
||||
value={configContext.val.toggleButtonContent}
|
||||
value={configContext.value.toggleButtonContent}
|
||||
></SelectInput>
|
||||
</Field>
|
||||
<SimpleToggleField
|
||||
|
|
|
|||
|
|
@ -4,12 +4,7 @@ import { Config } from 'utils/configHelper'
|
|||
|
||||
type Props = {}
|
||||
|
||||
type PartialValSet<T> = {
|
||||
val: T
|
||||
set: (val: Partial<T>) => void
|
||||
}
|
||||
|
||||
type ContextShape = PartialValSet<Config>
|
||||
type ContextShape = IO<Config, Partial<Config>>
|
||||
export type ConfigsContextShape = ContextShape
|
||||
|
||||
export const ConfigsContext = React.createContext<ContextShape | null>(null)
|
||||
|
|
@ -19,7 +14,7 @@ export function ConfigsContextWrapper(props: React.PropsWithChildren<Props>) {
|
|||
React.useEffect(() => {
|
||||
configsHelper.get().then(setConfigs)
|
||||
}, [])
|
||||
const set = React.useCallback(
|
||||
const onChange = React.useCallback(
|
||||
(updatedConfigs: Partial<Config>) => {
|
||||
const mergedConfigs = { ...configs, ...updatedConfigs } as Config
|
||||
configsHelper.set(mergedConfigs)
|
||||
|
|
@ -29,7 +24,7 @@ export function ConfigsContextWrapper(props: React.PropsWithChildren<Props>) {
|
|||
)
|
||||
if (configs === null) return null
|
||||
return (
|
||||
<ConfigsContext.Provider value={{ val: configs, set }}>
|
||||
<ConfigsContext.Provider value={{ value: configs, onChange: onChange }}>
|
||||
{props.children}
|
||||
</ConfigsContext.Provider>
|
||||
)
|
||||
|
|
@ -37,10 +32,10 @@ export function ConfigsContextWrapper(props: React.PropsWithChildren<Props>) {
|
|||
|
||||
export const useConfigs = useNonNullContext(ConfigsContext)
|
||||
|
||||
function useNonNullContext<T, R extends Exclude<T, null>>(theContext: React.Context<T>): () => R {
|
||||
function useNonNullContext<T>(theContext: React.Context<T | null>): () => T {
|
||||
return () => {
|
||||
const context = React.useContext(theContext)
|
||||
if (context === null) throw new Error(`Empty context`)
|
||||
return context as R
|
||||
return context
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ export const init: BoundMethodCreator = dispatch => async () => {
|
|||
const {
|
||||
props: { configContext },
|
||||
} = dispatch.get()
|
||||
const { accessToken } = configContext.val
|
||||
const { accessToken } = configContext.value
|
||||
|
||||
const guessDefaultBranch = 'master' // when to switch to 'main'?
|
||||
let getTreeData = platform.getTreeData(
|
||||
|
|
@ -139,7 +139,7 @@ export const handleError: BoundMethodCreator<[Error]> = dispatch => async err =>
|
|||
dispatch.set({ errorDueToAuth: true })
|
||||
} else if (err.message === errors.CONNECTION_BLOCKED) {
|
||||
const { props } = dispatch.get()
|
||||
if (props.configContext.val.accessToken) {
|
||||
if (props.configContext.value.accessToken) {
|
||||
dispatch.call(setError, `Cannot connect to ${platformName}.`)
|
||||
} else {
|
||||
dispatch.set({ errorDueToAuth: true })
|
||||
|
|
@ -161,10 +161,10 @@ export const toggleShowSideBar: BoundMethodCreator = dispatch => () => {
|
|||
dispatch.call(setShouldShow, !shouldShow)
|
||||
|
||||
const {
|
||||
val: { intelligentToggle },
|
||||
value: { intelligentToggle },
|
||||
} = configContext
|
||||
if (intelligentToggle !== null) {
|
||||
configContext.set({ intelligentToggle: !shouldShow })
|
||||
configContext.onChange({ intelligentToggle: !shouldShow })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
4
src/global.d.ts
vendored
4
src/global.d.ts
vendored
|
|
@ -18,9 +18,9 @@ type TreeNode = {
|
|||
accessDenied?: boolean
|
||||
}
|
||||
|
||||
type IO<T> = {
|
||||
type IO<T, ChangeT = T> = {
|
||||
value: T
|
||||
onChange(value: T): void
|
||||
onChange(value: ChangeT): void
|
||||
}
|
||||
|
||||
type Override<Original, Incoming> = Omit<Original, keyof Incoming> & Incoming
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import * as React from 'react'
|
||||
import { useStates } from './useStates'
|
||||
import { useStateIO } from './useStateIO'
|
||||
|
||||
export function useAsyncMemo<T, D extends any[] | readonly any[]>(
|
||||
factory: (dependencies: D) => T | Promise<T>,
|
||||
|
|
@ -7,10 +7,10 @@ export function useAsyncMemo<T, D extends any[] | readonly any[]>(
|
|||
initialValue: T,
|
||||
): T {
|
||||
const firstTime = React.useRef(true)
|
||||
const state = useStates<T>(() => initialValue)
|
||||
const state = useStateIO<T>(() => initialValue)
|
||||
React.useEffect(() => {
|
||||
if (firstTime.current) firstTime.current = false
|
||||
Promise.resolve(factory(deps)).then(consumed => state.set(() => consumed))
|
||||
Promise.resolve(factory(deps)).then(consumed => state.onChange(() => consumed))
|
||||
}, deps)
|
||||
return state.val
|
||||
return state.value
|
||||
}
|
||||
|
|
|
|||
11
src/utils/hooks/useStateIO.ts
Normal file
11
src/utils/hooks/useStateIO.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import * as React from 'react'
|
||||
|
||||
export function useStateIO<S>(
|
||||
initialState: S | (() => S),
|
||||
): {
|
||||
value: S
|
||||
onChange: React.Dispatch<React.SetStateAction<S>>
|
||||
} {
|
||||
const [value, onChange] = React.useState(initialState)
|
||||
return { value, onChange }
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
import * as React from 'react'
|
||||
|
||||
export function useStates<S>(
|
||||
initialState: S | (() => S),
|
||||
): {
|
||||
val: S
|
||||
set: React.Dispatch<React.SetStateAction<S>>
|
||||
} {
|
||||
const [val, set] = React.useState(initialState)
|
||||
return { val, set }
|
||||
}
|
||||
Loading…
Reference in a new issue