我是一个新手,用react 打字,try 了很多东西,但都不起作用.状态不起作用并获取类型脚本错误类型"userContextType"上不存在属性"状态和调度"|空' UserContRed.tsx

export const UserContRed = () => {

   //const context = useContext(ContRedContext)
    const {state , dispatch } = useContext(ContRedContext)
   
    const [firstname, setFirstname] = useState('')
    const [id, setId ] = useState(0)
    const [lastname, setLastname] = useState('')
 
    // let displayUsers =  context?.state.users.map( (u:any) => {
    let displayUsers =  state.users.map( (u:any) => {
        return(
            <ul key={u.id}>
                <li>{u.id}</li>
                <li>{u.firstname}</li>
                <li>{u.lastname}</li>
            </ul>
        ) 
    }) 
    const addUser = () => {
        const addUser = () => dispatch({type:ActionType.ADD, payload : {id:1,firstname:firstname, lastname:lastname}})
    }

    return(
        <div>
          <div>
            <label>Id: </label>
            <input type="text" onChange={(e)=>{setId(Number(e.target.value))}} />
          </div>
          <div>
            <label>Firstname: </label>
            <input type="text" onChange={(e)=>{setFirstname(e.target.value)}} />
          </div>
          <div>
            <label>Lastname: </label>
            <input type="text" onChange={(e)=>{setLastname(e.target.value)}} />
          </div>
            <button onClick={addUser}>sendToStore</button>

          
        </div>
       
    )
}

ContRed.tsx


export type User = {
    id: number;
    firstname: string;
    lastname: string; 
}

type contredProps = {
    children: React.ReactNode
}


export type IuserState = {
    users : User[]
}
const initialState: IuserState = {
    users : [
        {
            id:0,
            firstname:'',
            lastname: ''
        }
    ]
}
export enum ActionType {
    ADD="add",
    REMOVE="remove"
}


type  userAction = {
    type: ActionType,
    payload: User
}


export const reducer = (state: IuserState, action: userAction) : typeof initialState  => {
    
    switch(action.type){
        case "add": 
                return ({...state, users: [...state.users,
                                                    {id:action.payload.id,
                                                     firstname:action.payload.firstname,
                                                     lastname:action.payload.lastname   
                                                    }
                                                ]
                        })
        case "remove": 
                        return ({...state, users: [
                                    ...state.users.filter(data => data.id !== action.payload.id)]
                                })
        default:
            return state;
    }
}


type UserContextType = {
    state: IuserState
    dispatch: React.Dispatch<userAction>
}

export const ContRedContext = createContext<UserContextType|null>({
    state:initialState,
    dispatch: () => {}
})



export const ContRedContextProvier = ({children}:contredProps) => {
    
    const[state,dispatch] = useReducer(reducer,initialState as IuserState);
    const value : UserContextType = { state, dispatch}
    
    return(
        <ContRedContext.Provider value={value}>
            {children}
        </ContRedContext.Provider>
    )

}

App.tsx

    <ContRedContextProvier>
        <UserContRed/>
    </ContRedContextProvier>
    

我try 使用常数而不是go struct 化类型脚本错误消失,但它不会添加或更新状态.在我看来,Typescript 太难了,请解释或指导我做错了什么. 下面try 的Typescript 很好,但功能不起作用

  const context = useContext(ContRedContext)
  let displayUsers =  context?.state.users.map( (u:any) => { ...}
   const addUser = () => context?.state.dispatch({type:ActionType.ADD, payload : {id:1,firstname:firstname, lastname:lastname}})

try 过:

 const context = useContext(ContRedContext)
  let displayUsers =  context?.state.users.map( (u:any) => { ...}
   const addUser = () => context?.state.dispatch({type:ActionType.ADD, payload : {id:1,firstname:firstname, lastname:lastname}})

预期: 用户应该添加到状态并在子组件中呈现.

推荐答案

您已输入ContRedContext可为空,例如createContext<UserContextType | null>({ .... }),因此消费者需要在访问statedispatch之前使用空判断.

示例:

const context = useContext(ContRedContext);

if (!context) return null;
  
const { state, dispatch } = context; // not null 🙂

但您似乎从未传递null上下文值,即使是默认上下文值,而且可能没有必要这样做.

更新ContRedContext上下文类型声明以删除null类型:

export const ContRedContext = createContext<UserContextType>({
  state: initialState,
  dispatch: () => {}
});

带有addUser处理程序的UserContRed组件中还有一个额外问题.它声明了一个发出调度但从不调用它的函数.

发行代码:

const addUser = () => {
  const addUser = () => // <-- never called
    dispatch({
      type: ActionType.ADD,
      payload: { id, firstname: firstname, lastname: lastname }
    });
};

更新为仅拨打dispatch:

const addUser = () => {
  dispatch({
    type: ActionType.ADD,
    payload: { id, firstname, lastname }
  });
};

Typescript相关问答推荐

已定义但从未使用通用推断的错误

在控制器中使用@ DeliverGuards时实现循环依赖项时未定义的依赖项

为什么仅对对象而不对简单类型需要满足?

相同端点具有不同响应时的RTKQuery类型定义

使用带有RxJS主题的服务在Angular中的组件之间传递数据

有没有一种方法可以在保持类型的可选状态的同时更改类型?

类型脚本泛型最初推断然后设置

如何设置绝对路径和相对路径的类型?

为什么在这个例子中,我把缺少的属性添加到对象中时,TypeScrip没有拾取,如何修复?

缩小并集子键后重新构造类型

TS2339:类型{}上不存在属性消息

是否存在类型联合的替代方案,其中包括仅在某些替代方案中存在的可选属性?

是否有可能避免此泛型函数体中的类型断言?

如何使这种一对一关系在旧表上起作用?

如何在try 运行独立的文字脚本Angular 项目时修复Visual Studio中的MODULE_NOT_FOUND

TaskListProps[]类型不可分配给TaskListProps类型

如何处理可能为空的变量...我知道这不是Null?

定义一个只允许来自另一个类型的特定字符串文字的类型的最佳方式

断言同级为true或抛出错误的Typescript函数

我应该使用服务方法(依赖于可观察的)在组件中进行计算吗?