如何为以下 contextapi 代码设置 useReducer useContext 的 Typescript 类型?
How do I set Typescript types for useReducer useContext for the following contextapi code?
我想在以下代码中使用正确的 TS 类型,而不是任何类型。我是react TS新手,请帮忙...
如何为以下上下文设置 useReducer useContext 的打字稿类型 API 代码:
import React, {createContext, Dispatch} from 'react';
import {firebaseUser} from '../@types/User';
interface Actions {
SET_IMAGENAME: string;
SET_USER: string;
}
export const Actions: Actions = {
SET_IMAGENAME: 'SET_IMAGENAME',
SET_USER: 'SET_USER',
};
function action(type: string) {
return {type};
}
function actionPayload(type: string, payload: any) { //here
return {type, payload};
}
export const Dispatches = {
setImageName: action,
setUser: actionPayload,
};
interface State {
imgName: string;
user: firebaseUser;
}
const initialState = {
imgName: '',
user: {} as firebaseUser,
};
function reducer(state = initialState, action: {type: string; payload: any}) { //here
switch (action.type) {
case Actions.SET_IMAGENAME:
return {...state, imgName: 'sample image'};
case Actions.SET_USER:
return {...state, user: action.payload};
default:
return state;
}
}
export const Store = createContext<{
state: State;
dispatch: Dispatch<any>; //here
}>({
state: initialState,
dispatch: () => null,
});
export function StoreProvider({children}: JSX.ElementChildrenAttribute): JSX.Element {
const [state, dispatch] = React.useReducer(reducer, initialState);
return <Store.Provider value={{state, dispatch}}>{children}</Store.Provider>;
}
谁能帮帮我,不胜感激?
谢谢
这真的取决于有效负载可以包含什么,它可以包含图像字符串或您可以设置的 FirebaseUser 实例 payload: string | FirebaseUser
import React, {createContext, Dispatch} from 'react';
import {firebaseUser} from '../@types/User';
interface Actions {
SET_IMAGENAME: string;
SET_USER: string;
}
export const Actions: Actions = {
SET_IMAGENAME: 'SET_IMAGENAME',
SET_USER: 'SET_USER',
};
function action(type: string) {
return {type};
}
// If payload can contain string of image or FirebaseUser instance
// it will be string | FirebaseUser
// if payload will only contain FirebaseUser instance you just need payload: FirebaseUser
export type ActionType = {
type: string,
payload: string | FirebaseUser
}
// If payload can contain string of image or FirebaseUser instance
// it will be string | FirebaseUser
// if payload will only contain FirebaseUser instance you just need payload: FirebaseUser
function actionPayload(type: string, payload: string | FirebaseUser ) { //here
return {type, payload};
}
export const Dispatches = {
setImageName: action,
setUser: actionPayload,
};
interface State {
imgName: string;
user: FirebaseUser;
}
const initialState = {
imgName: '',
user: {} as firebaseUser,
};
// set Action type here
function reducer(state = initialState, action: ActionType) {
switch (action.type) {
case Actions.SET_IMAGENAME:
// need to cast type herer
return {...state, imgName: action.payload as string};
case Actions.SET_USER:
// need to cast type herer
return {...state, user: action.payload as firebaseUser};
default:
return state;
}
}
export const Store = createContext<{
state: State;
dispatch: Dispatch<ActionType>; //action type here
}>({
state: initialState,
dispatch: () => null,
});
export function StoreProvider({children}: JSX.ElementChildrenAttribute): JSX.Element {
const [state, dispatch] = React.useReducer(reducer, initialState);
return <Store.Provider value={{state, dispatch}}>{children}</Store.Provider>;
}
这也是我的解决方案,通过添加类型文件来使您的文件结构更加整洁,我希望您觉得它有用:
myCodesandboxRepo
我希望这个解决方案能给出好的主意。
https://gist.github.com/sw-yx/f18fe6dd4c43fddb3a4971e80114a052
https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context/#extended-example
export function createCtx<StateType, ActionType>(
reducer: React.Reducer<StateType, ActionType>,
initialState: StateType,
) {
const defaultDispatch: React.Dispatch<ActionType> = () => initialState // we never actually use this
const ctx = React.createContext({
state: initialState,
dispatch: defaultDispatch, // just to mock out the dispatch type and make it not optioanl
})
function Provider(props: React.PropsWithChildren<{}>) {
const [state, dispatch] = React.useReducer<React.Reducer<StateType, ActionType>>(reducer, initialState)
return <ctx.Provider value={{ state, dispatch }} {...props} />
}
return [ctx, Provider] as const
}
// usage
const initialState = { count: 0 }
type AppState = typeof initialState
type Action =
| { type: 'increment' }
| { type: 'add'; payload: number }
| { type: 'minus'; payload: number }
| { type: 'decrement' }
function reducer(state: AppState, action: Action): AppState {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
case 'add':
return { count: state.count + action.payload }
case 'minus':
return { count: state.count - action.payload }
default:
throw new Error()
}
}
const [ctx, CountProvider] = createCtx(reducer, initialState)
export const CountContext = ctx
// top level example usage
export function App() {
return (
<CountProvider>
<Counter />
</CountProvider>
)
}
// example usage inside a component
function Counter() {
const { state, dispatch } = React.useContext(CountContext)
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'add', payload: 5 })}>+5</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'minus', payload: 5 })}>+5</button>
</div>
)
}
我想在以下代码中使用正确的 TS 类型,而不是任何类型。我是react TS新手,请帮忙...
如何为以下上下文设置 useReducer useContext 的打字稿类型 API 代码:
import React, {createContext, Dispatch} from 'react';
import {firebaseUser} from '../@types/User';
interface Actions {
SET_IMAGENAME: string;
SET_USER: string;
}
export const Actions: Actions = {
SET_IMAGENAME: 'SET_IMAGENAME',
SET_USER: 'SET_USER',
};
function action(type: string) {
return {type};
}
function actionPayload(type: string, payload: any) { //here
return {type, payload};
}
export const Dispatches = {
setImageName: action,
setUser: actionPayload,
};
interface State {
imgName: string;
user: firebaseUser;
}
const initialState = {
imgName: '',
user: {} as firebaseUser,
};
function reducer(state = initialState, action: {type: string; payload: any}) { //here
switch (action.type) {
case Actions.SET_IMAGENAME:
return {...state, imgName: 'sample image'};
case Actions.SET_USER:
return {...state, user: action.payload};
default:
return state;
}
}
export const Store = createContext<{
state: State;
dispatch: Dispatch<any>; //here
}>({
state: initialState,
dispatch: () => null,
});
export function StoreProvider({children}: JSX.ElementChildrenAttribute): JSX.Element {
const [state, dispatch] = React.useReducer(reducer, initialState);
return <Store.Provider value={{state, dispatch}}>{children}</Store.Provider>;
}
谁能帮帮我,不胜感激?
谢谢
这真的取决于有效负载可以包含什么,它可以包含图像字符串或您可以设置的 FirebaseUser 实例 payload: string | FirebaseUser
import React, {createContext, Dispatch} from 'react';
import {firebaseUser} from '../@types/User';
interface Actions {
SET_IMAGENAME: string;
SET_USER: string;
}
export const Actions: Actions = {
SET_IMAGENAME: 'SET_IMAGENAME',
SET_USER: 'SET_USER',
};
function action(type: string) {
return {type};
}
// If payload can contain string of image or FirebaseUser instance
// it will be string | FirebaseUser
// if payload will only contain FirebaseUser instance you just need payload: FirebaseUser
export type ActionType = {
type: string,
payload: string | FirebaseUser
}
// If payload can contain string of image or FirebaseUser instance
// it will be string | FirebaseUser
// if payload will only contain FirebaseUser instance you just need payload: FirebaseUser
function actionPayload(type: string, payload: string | FirebaseUser ) { //here
return {type, payload};
}
export const Dispatches = {
setImageName: action,
setUser: actionPayload,
};
interface State {
imgName: string;
user: FirebaseUser;
}
const initialState = {
imgName: '',
user: {} as firebaseUser,
};
// set Action type here
function reducer(state = initialState, action: ActionType) {
switch (action.type) {
case Actions.SET_IMAGENAME:
// need to cast type herer
return {...state, imgName: action.payload as string};
case Actions.SET_USER:
// need to cast type herer
return {...state, user: action.payload as firebaseUser};
default:
return state;
}
}
export const Store = createContext<{
state: State;
dispatch: Dispatch<ActionType>; //action type here
}>({
state: initialState,
dispatch: () => null,
});
export function StoreProvider({children}: JSX.ElementChildrenAttribute): JSX.Element {
const [state, dispatch] = React.useReducer(reducer, initialState);
return <Store.Provider value={{state, dispatch}}>{children}</Store.Provider>;
}
这也是我的解决方案,通过添加类型文件来使您的文件结构更加整洁,我希望您觉得它有用: myCodesandboxRepo
我希望这个解决方案能给出好的主意。
https://gist.github.com/sw-yx/f18fe6dd4c43fddb3a4971e80114a052
https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/context/#extended-example
export function createCtx<StateType, ActionType>(
reducer: React.Reducer<StateType, ActionType>,
initialState: StateType,
) {
const defaultDispatch: React.Dispatch<ActionType> = () => initialState // we never actually use this
const ctx = React.createContext({
state: initialState,
dispatch: defaultDispatch, // just to mock out the dispatch type and make it not optioanl
})
function Provider(props: React.PropsWithChildren<{}>) {
const [state, dispatch] = React.useReducer<React.Reducer<StateType, ActionType>>(reducer, initialState)
return <ctx.Provider value={{ state, dispatch }} {...props} />
}
return [ctx, Provider] as const
}
// usage
const initialState = { count: 0 }
type AppState = typeof initialState
type Action =
| { type: 'increment' }
| { type: 'add'; payload: number }
| { type: 'minus'; payload: number }
| { type: 'decrement' }
function reducer(state: AppState, action: Action): AppState {
switch (action.type) {
case 'increment':
return { count: state.count + 1 }
case 'decrement':
return { count: state.count - 1 }
case 'add':
return { count: state.count + action.payload }
case 'minus':
return { count: state.count - action.payload }
default:
throw new Error()
}
}
const [ctx, CountProvider] = createCtx(reducer, initialState)
export const CountContext = ctx
// top level example usage
export function App() {
return (
<CountProvider>
<Counter />
</CountProvider>
)
}
// example usage inside a component
function Counter() {
const { state, dispatch } = React.useContext(CountContext)
return (
<div>
Count: {state.count}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'add', payload: 5 })}>+5</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
<button onClick={() => dispatch({ type: 'minus', payload: 5 })}>+5</button>
</div>
)
}