我正在编写一个名为useRequest
的自定义挂钩,用于管理数据获取。用户需要传递在promise中解析的数据的类型,以及默认为unknown
类型的可选错误类型
以下是实现。
enum Status {
pending = "pending",
resolved = "resolved",
rejected = "rejected"
}
type State<R, E = unknown> = {
status: Status;
data: null | R;
error: null | E;
};
type Action<R, E = unknown> =
| { type: Status.pending }
| { type: Status.resolved; data: R }
| { type: Status.rejected; error: E };
function reducer<R, E>(state: State<R, E>, action: Action<R, E>): State<R, E> {
switch (action.type) {
case Status.pending: {
return { status: Status.pending, data: null, error: null };
}
case Status.resolved: {
return { status: Status.resolved, data: action.data, error: null };
}
case Status.rejected: {
return { status: Status.rejected, data: null, error: action.error };
}
default: {
throw new Error(`unhandled action type`);
}
}
}
function useRequest<R, E = unknown>(intialState: State<R, E>) {
const [state, unsafeDispatch] = React.useReducer(reducer, {
status: Status.pending,
data: null,
error: null,
...intialState
});
// omit implementation details
}
但是,state
不是属性类型的,它的类型是State<unknown, unknown>
我试图在现有问题中寻找解决方案,并在useReducer中为返回的参数找到了这种Generic类型。然而,它的方法似乎也不起作用。即
function createReducer<R, E = unknown>() {
return function reducer<R, E>(
state: State<R, E>,
action: Action<R, E>
): State<R, E> {
switch (action.type) {
case Status.pending: {
return { status: Status.pending, data: null, error: null }
}
case Status.resolved: {
return { status: Status.resolved, data: action.data, error: null }
}
case Status.rejected: {
return { status: Status.rejected, data: null, error: action.error }
}
default: {
throw new Error(`unhandled action type`)
}
}
}
}
export default function useRequest<R, E = unknown>(intialState: State<R, E>) {
const reducer = createReducer<R, E>()
const [state, unsafeDispatch] = useReducer(reducer, {
status: Status.pending,
data: null,
error: null,
})
state
的类型仍然是State<unknown, unknown>
有人能帮我在这里正确键入useReducer
吗?我也在这里寻找任何其他的反馈/建议。谢谢
这是你可以玩的现场演示https://codesandbox.io/s/usereducer-7vvqz
您的reducer函数需要将泛型传递给它,所以让您的reductor返回一个函数
即。
function reducer<R, E>() {
return function actualReducer(state: State<R, E>, action: Action<R, E>): State<R, E> {
...
}
function useRequest<R, E = unknown>(intialState: State<R, E>) {
const [state, unsafeDispatch] = React.useReducer(reducer<R>(), {
...
}
}
请注意,这是在每次渲染时调用一个函数,这可能不是性能性的(您可以将其存储起来以抵消这一点(,但它可以在中工作
编辑:刚刚注意到OP的第二个实现有这个建议,只是把这个答案留在这里,因为它对我有效,并且清楚地突出了实现之间的差异