问题描述
我是第一次学习 ts 的初学者。预先感谢您分享您的知识。 我正在制作一个todolist。我用反应来完成它。但是现在我用 react 和 typescript 一起来完成代码。
在我看来,'reducer' 工作不正常。我该如何操作?如果你让我知道,我将不胜感激。这是带有表面错误的“App.tsx”代码。
import React,{ useState } from "react";
import Add from "./Add";
import List from "./List";
import Todo from "./Todo";
import Title from "./Title";
import Progress from "./Progress";
import styled from "styled-components";
interface ITodo {
todos: string;
completed: boolean;
}
function App() {
const { todos,completed } = useState<ITodo>(); ? Error part
return (
<Title>
<Add />
<Progress />
<Lists>
<List title={todos.length !== 0 ? "To Dos" : ""}>
{todos.map((todo: any) => (
<Todo key={todo.id} id={todo.id} text={todo.text} isCompleted={false} />
))}
</List>
<List title={completed.length !== 0 ? "Completed" : ""}>
{completed.map((todo: any) => (
<Todo key={todo.id} id={todo.id} text
{...todo.text} isCompleted />
))}
</List>
</Lists>
</Title>
);
}
export default App;
import { v4 as uuidv4 } from "uuid";
import { ADD,DEL,COMPLETE,UNCOMPLETE,EDIT } from "./actions";
export const initialState = {
todos: [],completed: [],};
const reducer = ({ state,action }: any) => {
switch (action) {
case ADD:
return {
...state,todos: [...state.todos,{ text: action.payload,id: uuidv4() }],};
case DEL:
return {
...state,todos: state.todos.filter((todo: { id: number; }) => todo.id !== action.payload),};
case COMPLETE:
const target = state.todos.find((todo: { id: number; }) => todo.id === action.payload);
return {
...state,completed: [...state.completed,{ ...target }],};
case UNCOMPLETE:
const aTarget = state.completed.find(
(todo: { id: any; }) => todo.id === action.payload
);
return {
...state,{ ...aTarget }],completed: state.completed.filter(
(complete: { id: number; }) => complete.id !== action.payload
),};
case EDIT:
const bTarget = state.todos.find((todo: { id: number; }) => todo.id === action.id);
const rest = state.todos.filter((todo: { id: number; }) => todo.id !== action.id);
return {
...state,todos: rest.concat({ ...bTarget,text: action.payload }),};
default:
return;
}
};
export default reducer;
import React,{ createContext,useReducer,useContext } from 'react';
import reducer,{ initialState } from "./reducer";
export type Todo = {
id: number;
text: string;
done: boolean;
};
export type Todosstate = Todo[];
const TodosContext = createContext<Todosstate | any>(undefined);
const TodosProvider = ({ children }: { children: React.ReactNode }) => {
const [state,dispatch] = useReducer(reducer,initialState);
return (
<TodosContext.Provider value={{ state,dispatch }}>
{children}
</TodosContext.Provider>
);
};
export const usedispatch = () => {
const { dispatch } = useContext(TodosContext);
return dispatch;
};
export const useState = () => {
const { state } = useContext(TodosContext);
return state;
};
export default TodosProvider;
解决方法
这里发生的事情是由于命名混乱。您创建了一个自定义钩子 useState
,它与一个内置的 React 钩子同名,但您使用了错误的钩子。
这里出现错误:
const { toDos,completed } = useState<ITodo>(); ? Error part
因此:
import React,{ useState } from "react";
您想使用自定义 useState
钩子,它返回一个具有 toDos
和 completed
属性的对象。但是,您没有导入该钩子,而是导入了内置的 React 钩子 useState
,它返回一个包含两个条目(state
和 setState
)的数组。
进入 context.tsx
并将您的自定义挂钩重命名为不那么模糊的名称,例如 useTodosState
和 useTodosDispatch
。这不是严格要求的,但它会让生活变得更轻松!
然后进入 App.tsx
并将 useState
替换为 useTodosState
,确保从 context.tsx
导入它。既然您已经确定要使用哪个钩子,您就无需担心 IDE 会自动从 React 导入 useState
。