“Array is not iterable in useReducer()” 可以翻译为 “在 useReducer() 中数组不可迭代”。

huangapple go评论62阅读模式
英文:

Array is not iterable in useReducer()

问题

在练习React hooks时,我使用ReactTS编写了一个简单的待办事项网站。我遇到了一个问题,即尽管在State类型中已经定义为TodoProps[],但我不断收到一个错误,即我的待办事项数组不可迭代。

错误通常发生在“添加”按钮点击之后。

错误:state.todos 不可迭代

如果我写console.log(state.todos),我会收到undefined

我在这里检查了代码,它似乎与我的代码相同,但无论如何我无法解决这个问题。

(错误位置在代码中有标记)

TodoProps:

export interface TodoProps {
      title: string
      id: number
      todoKey?: number
      completed: boolean
}

LayoutContext.tsx:

import { createContext, useState, ReactNode } from 'react';

export const TodoListContext = createContext<any>({});
export const TitleContext = createContext<any>({});

type LayoutContextProps = {
      children: ReactNode
}

export const LayoutContext = ({ children }: LayoutContextProps): JSX.Element => {
      const [title, setTitle] = useState<string>('');
      const [todoList, setTodoList] = useState<object[]>([
            { title: 'Todo 1', id: 418759 },
            { title: 'Todo 2', id: 440123 }
      ]);

      return (
            <TitleContext.Provider value={{ title, setTitle }}>
                  <TodoListContext.Provider value={{ todoList, setTodoList }}>
                        {children}
                  </TodoListContext.Provider>
            </TitleContext.Provider>
      );
}

Layout.tsx:

import { Button, Todos, Input } from 'Components';
import { LayoutContext } from 'Context/LayoutContext';
import cn from 'classnames';
import styles from './Layout.module.scss';

export const Layout = (): JSX.Element => {
      return (
            <section className={cn(styles.layout)}>
                  <LayoutContext>
                        <Todos/>
                        <Input/>
                        <Button>Add</Button>
                  </LayoutContext>
            </section>
      );
}

Button.tsx:

import styles from './Button.module.scss';
import { ButtonHTMLAttributes, DetailedHTMLProps, ReactNode, useReducer, useContext, useEffect } from 'react';
import { TodoListContext, TitleContext } from '../../Context/LayoutContext';
import { TodoProps } from 'Components/TodoComponent/Todo';

interface ButtonProps extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
      children: ReactNode
}

export const Button = ({ children }: ButtonProps): JSX.Element => {
      const { todoList } = useContext(TodoListContext);
      const { title, setTitle } = useContext(TitleContext);

      type State = { todos: TodoProps[] };

      type Action = { type: 'addTodo', payload: string };

      const reducer = (state: State, action: Action) => {
            switch (action.type) {
                  case 'addTodo':
                        const newTodoCard: TodoProps = { 
                              title: action.payload,
                              id: Math.floor(Math.random() % 10),
                              completed: false
                        };

                        console.log(todoList);
                        console.log(state.todos);

                        return { 
                              // 这里出错
                              todos: [...state.todos, newTodoCard]
                        };
            }
      }

      const [state, dispatch] = useReducer(reducer, todoList);

      const handleAdd = (e: any) => {
            e.preventDefault();

            dispatch({ type: 'addTodo', payload: title });
            setTitle('');
      }

      return (
            <button
                  type='submit'
                  onClick={handleAdd}
                  className={styles.button}
            >{children}</button>
      );
}

不知道是否还可以提供更多信息。

英文:

To practice React hooks I wrote a simple todo site with ReactTS. I faced a problem that I keep receiving an error that my todos array is not iterable, despite it is defined as TodoProps[] in State type

Error occurs logically after 'add' button click

Error: state.todos is not iterable

If I write console.log(state.todos) I receive undefined

I checked code on medium and it seems to be identical to mine, but anyway I cannot resolve this issue.

(Error place marked in code)

TodoProps:

export interface TodoProps {
title: string
id: number
todoKey?: number
completed: boolean
}

LayoutContext.tsx:

import { createContext, useState, ReactNode } from &#39;react&#39;
export const TodoListContext = createContext&lt;any&gt;({})
export const TitleContext = createContext&lt;any&gt;({})
type LayoutContextProps = {
children: ReactNode
}
export const LayoutContext = ({ children }: LayoutContextProps): JSX.Element =&gt; {
const [title, setTitle] = useState&lt;string&gt;(&#39;&#39;)
const [todoList, setTodoList] = useState&lt;object[]&gt;([
{title: &#39;Todo 1&#39;, id: 418759},
{title: &#39;Todo 2&#39;, id: 440123}
])
return (
&lt;TitleContext.Provider value={{ title, setTitle }}&gt;
&lt;TodoListContext.Provider value={{ todoList, setTodoList }}&gt;
{children}
&lt;/TodoListContext.Provider&gt;
&lt;/TitleContext.Provider&gt;
)
}

Layout.tsx:

import { Button, Todos, Input } from &#39;Components&#39;
import { LayoutContext } from &#39;Context/LayoutContext&#39;
import cn from &#39;classnames&#39;
import styles from &#39;./Layout.module.scss&#39;
export const Layout = (): JSX.Element =&gt; {
return (
&lt;section className={cn(styles.layout)}&gt;
&lt;LayoutContext&gt;
&lt;Todos/&gt;
&lt;Input/&gt;
&lt;Button&gt;Add&lt;/Button&gt;
&lt;/LayoutContext&gt;
&lt;/section&gt;
)
}

Button.tsx:

import styles from &#39;./Button.module.scss&#39;
import { ButtonHTMLAttributes, DetailedHTMLProps, ReactNode, useReducer, useContext, useEffect } from &#39;react&#39;;
import { TodoListContext, TitleContext } from &#39;../../Context/LayoutContext&#39;;
import { TodoProps } from &#39;Components/TodoComponent/Todo&#39;;
interface ButtonProps extends DetailedHTMLProps&lt;ButtonHTMLAttributes&lt;HTMLButtonElement&gt;, HTMLButtonElement&gt; {
children: ReactNode
}
export const Button = ({ children }: ButtonProps): JSX.Element =&gt; {
const { todoList } = useContext(TodoListContext)
const { title, setTitle } = useContext(TitleContext)
type State = { todos: TodoProps[] }
type Action = { type: &#39;addTodo&#39;, payload: string }
const reducer = (state: State, action: Action) =&gt; {
switch (action.type) {
case &#39;addTodo&#39;:
const newTodoCard: TodoProps = { 
title: action.payload,
id: Math.floor(Math.random() % 10),
completed: false
}
console.log(todoList)
console.log(state.todos)
return { 
Error here
\/\/\/\/\/\/\/\/\/\/\/\/\/\/
todos: [...state.todos, newTodoCard]
/\/\/\/\/\/\/\/\/\/\/\/\/\/\ 
}
}
}
const [state, dispatch] = useReducer(reducer, todoList)
const handleAdd = (e: any) =&gt; {
e.preventDefault()
dispatch({ type: &#39;addTodo&#39;, payload: title})
setTitle(&#39;&#39;)
}
return (
&lt;button
type=&#39;submit&#39;
onClick={handleAdd}
className={styles.button}
&gt;{children}&lt;/button&gt;
)
}

Don't know if I can add any more information..

答案1

得分: 3

将数组传递给你的 reducer 的初始状态,然后在 reducer 中将其访问为对象,所以你只需要更改以下这些行:

const [state, dispatch] = useReducer(reducer, todoList)

const [state, dispatch] = useReducer(reducer, { todos: todoList });

然后你就可以继续进行。

英文:

You are passing an array to the initial state into your reducer and accessing it as an object in your reducer so you just need to change these lines

from

const [state, dispatch] = useReducer(reducer, todoList)

To

const [state, dispatch] = useReducer(reducer, { todos: todoList });

and you are good to go.

huangapple
  • 本文由 发表于 2023年2月27日 03:58:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75574666.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定