在状态中反应上下文和可为空的值
React context and nullable values in state
我正在尝试在 React 中创建一个上下文,它将保存一些由接口定义的值(下例中的 Client
)。我的问题是它要求我在状态接口 (ClientState
) 中使该字段可为空,这意味着我必须在使用上下文的任何地方检查空值。我想避免这种情况。
示例代码:
interface Client {
value1: string,
value2: number
}
interface ClientState {
client?: Client
}
const initialState: ClientState = {
client: undefined
}
const ClientContext = React.createContext<ClientState>(initialState);
export const useClient = (): ClientState => useContext(ClientContext);
export const EmployeeContextProvider = ({ children }: PropsWithChildren<{}>) => {
const [state, setState] = useState({});
// abstracted, not relevant to this problem
const loadFiles = () => {
setState(
{
value1: "test",
value2: 1
}
)
}
useEffect(() => loadFiles(), []);
return (
<ClientContext.Provider value={state}>
{children}
</ClientContext.Provider>
)
}
到目前为止,我已经尝试并认为不满意:
- 为
initialState
中的 client
字段提供一个虚拟对象。这个的问题是这个的真实版本有大量的这些字段,意味着有很多伪代码。
- 为
Client
接口的成员添加对 useClient()
的检查,与 1. 相同的问题
另外一个半相关的是我不需要在初始化之外修改这个上下文,它是只读的完全没问题。
client
需要是可选的,因为它的值是从初始化为空对象的 state
设置的。 state
的类型被推断为 ClientState
.
useState<ClientState>({})
要求 ClientState
的所有属性都是可选的。
您可以强制 TypeScript 接受一个空(虚拟)对象 ,就好像它 使用 useState({} as ClientState)
遵守 ClientState 一样,但这意味着您的 Provider 确实会提供一个不可用的对象客户端直到 setState
被真正的客户端调用。
但这似乎是你更喜欢的问题,而不是每次你想使用客户端时检查 null/undefined...
TypeScript 或许可以让您远离自我。如果您的客户端确实可以未定义,那么您应该每次使用它时检查它!
我想这就是你想要的。
您的 ClientState 类型似乎只用于允许未定义客户端,您说您不想要,所以我假设您不想拥有它。此外,它与您设置 Client 而不是 ClientState 的 setState 调用冲突。
这允许状态为空的客户端,但不在上下文中。守卫确保在设置客户端之前不会呈现上下文及其子项。
import React, { PropsWithChildren, useContext, useEffect, useState } from "react";
interface Client {
value1: string,
value2: number
}
// Note: ClientContext is initialised with an unusable Client object
const ClientContext = React.createContext<Client>({} as Client);
export const useClient = (): Client => useContext(ClientContext);
export const EmployeeContextProvider = ({ children }: PropsWithChildren<{}>) => {
// We allow state to be set to null
const [state, setState] = useState<Client | null>(null);
// abstracted, not relevant to this problem
const loadFiles = () => {
setState(
{
value1: "test",
value2: 1
}
)
}
useEffect(() => loadFiles(), []);
// Guard against null so that state can be provided as a Client
return (
state != null ?
<ClientContext.Provider value={state} >
{children}
</ClientContext.Provider>
: null
)
}
我正在尝试在 React 中创建一个上下文,它将保存一些由接口定义的值(下例中的 Client
)。我的问题是它要求我在状态接口 (ClientState
) 中使该字段可为空,这意味着我必须在使用上下文的任何地方检查空值。我想避免这种情况。
示例代码:
interface Client {
value1: string,
value2: number
}
interface ClientState {
client?: Client
}
const initialState: ClientState = {
client: undefined
}
const ClientContext = React.createContext<ClientState>(initialState);
export const useClient = (): ClientState => useContext(ClientContext);
export const EmployeeContextProvider = ({ children }: PropsWithChildren<{}>) => {
const [state, setState] = useState({});
// abstracted, not relevant to this problem
const loadFiles = () => {
setState(
{
value1: "test",
value2: 1
}
)
}
useEffect(() => loadFiles(), []);
return (
<ClientContext.Provider value={state}>
{children}
</ClientContext.Provider>
)
}
到目前为止,我已经尝试并认为不满意:
- 为
initialState
中的client
字段提供一个虚拟对象。这个的问题是这个的真实版本有大量的这些字段,意味着有很多伪代码。 - 为
Client
接口的成员添加对useClient()
的检查,与 1. 相同的问题
另外一个半相关的是我不需要在初始化之外修改这个上下文,它是只读的完全没问题。
client
需要是可选的,因为它的值是从初始化为空对象的 state
设置的。 state
的类型被推断为 ClientState
.
useState<ClientState>({})
要求 ClientState
的所有属性都是可选的。
您可以强制 TypeScript 接受一个空(虚拟)对象 ,就好像它 使用 useState({} as ClientState)
遵守 ClientState 一样,但这意味着您的 Provider 确实会提供一个不可用的对象客户端直到 setState
被真正的客户端调用。
但这似乎是你更喜欢的问题,而不是每次你想使用客户端时检查 null/undefined...
TypeScript 或许可以让您远离自我。如果您的客户端确实可以未定义,那么您应该每次使用它时检查它!
我想这就是你想要的。
您的 ClientState 类型似乎只用于允许未定义客户端,您说您不想要,所以我假设您不想拥有它。此外,它与您设置 Client 而不是 ClientState 的 setState 调用冲突。
这允许状态为空的客户端,但不在上下文中。守卫确保在设置客户端之前不会呈现上下文及其子项。
import React, { PropsWithChildren, useContext, useEffect, useState } from "react";
interface Client {
value1: string,
value2: number
}
// Note: ClientContext is initialised with an unusable Client object
const ClientContext = React.createContext<Client>({} as Client);
export const useClient = (): Client => useContext(ClientContext);
export const EmployeeContextProvider = ({ children }: PropsWithChildren<{}>) => {
// We allow state to be set to null
const [state, setState] = useState<Client | null>(null);
// abstracted, not relevant to this problem
const loadFiles = () => {
setState(
{
value1: "test",
value2: 1
}
)
}
useEffect(() => loadFiles(), []);
// Guard against null so that state can be provided as a Client
return (
state != null ?
<ClientContext.Provider value={state} >
{children}
</ClientContext.Provider>
: null
)
}