reactjs 我的接口创建和赋值有什么问题吗?

iyfjxgzm  于 2023-06-05  发布在  React
关注(0)|答案(2)|浏览(142)

我是用React Libray构建Web的新手,并使用next.js和typscript来创建Web应用程序。我在试着做一个待办事项列表的网络应用。
我创建了一个接口,用于收集列表数据,如下所示:

interface listData {
  text: string,
  isDone: boolean,
  viewMode?: { display: '' },
  editMode?: { display: 'none' },
}

const [list, setList] = useState<listData[]>([]);

const addList = (item: any) => {
  if (item !== "") {
    const newList = [...list, { text: item, isDone: false, viewMode: { display: '' }, editMode: { display: 'none' } }];
    localStorage.setItem('listData', JSON.stringify([...list, { text: item, isDone: false, viewMode: { display: '' }, editMode: { display: 'none' } }]));
    setList(newList);
  };
}

我在setList(newList)时得到了下面的vscode错误:

Argument of type '(listData | { text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; })[]' is not assignable to parameter of type 'SetStateAction<listData[]>'.
  Type '(listData | { text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; })[]' is not assignable to type 'listData[]'.
    Type 'listData | { text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; }' is not assignable to type 'listData'.
      Type '{ text: string; isDone: boolean; viewMode: { display: string; }; editMode: { display: string; }; }' is not assignable to type 'listData'.
        The types of 'viewMode.display' are incompatible between these types.
          Type 'string' is not assignable to type '""'.ts(2345)

viewMode和editMode是为display css构建的,用于显示将显示哪个标签,比如当用户按下编辑按钮时,然后是viewmode.display:'none',否则为editMode。display:没有
现在我有一个关于addList赋值的问题,请看下图。我不知道现在addList函数中的问题是什么,当我setList(newList)。希望有人能告诉我我在哪里工作,真的很感谢。

return (
  <>
    <div className={styles.bodyOuterDiv} >
      ...
        <ul >
          {list.map((item, index) => {
            return (
              <li key={index} className={styles.todoListOuterLi} >
                <div className={item.isDone ? styles.todoListItemsWithIsDone : styles.todoListItems} style={item.viewMode}>
                        {item.text}
                </div>
                <textarea className={styles.todoListTextArea} value={item.text} onChange={(e) => { setItem(e.target.value) }} style={item.editMode} />
                      ...
               </li>
             );
          })}
        </ul>
       ...
     </div>
  </>
);
lvjbypge

lvjbypge1#

问题是,因为你没有newList或其中的新对象的类型注解,TypeScript * 从属性值的类型推断 * 这些属性的类型。当它这样做时,TypeScript将"""none"推断为string类型(而不是字符串文字类型"""none"),但您的接口需要字符串文字类型"""none"
有几种方法可以解决这个问题。可能最直接的方法是告诉TypeScript newList是一个listData[](但请继续阅读,还有一些其他问题):

const addList = (item: any) => {
    if (item !== "") {
        const newList: listData[] = [ // <===========
            ...list,
            { text: item, isDone: false, viewMode: { display: "" }, editMode: { display: "none" } },
        ];
        localStorage.setItem(
            "listData",
            JSON.stringify([
                ...list,
                {
                    text: item,
                    isDone: false,
                    viewMode: { display: "" },
                    editMode: { display: "none" },
                },
            ])
        );
        setList(newList);
    }
};

Playground链接
旁注:item参数的类型应该是string,而不是any

const addList = (item: string) => {
    // −−−−−−−−−−−−−−−−^^^^^^

通过将其设置为any,您可以执行addList(42),这将在列表中放置一个具有text: 42的对象,这不是类型所说的那样。
也就是说,还有几件事:
1.每当基于现有状态设置状态时,最好使用状态设置器的回调形式,而不是依赖于addList关闭的list副本,因为那可能是过时的。
1.没有理由重复添加新项的代码,只需在本地存储中存储时使用newList即可。
所以:

const addList = (item: string) => {
    if (item !== "") {
        setList((list) => {
            const newList: listData[] = [
                ...list,
                {
                    text: item,
                    isDone: false,
                    viewMode: { display: "" },
                    editMode: { display: "none" },
                },
            ];
            localStorage.setItem("listData", JSON.stringify(newList));
            return newList;
        });
    }
};

Playground链接
使用回调表单还可以记忆addList,如果要将其传递到的组件是记忆的,这可能很有用。每次都给该组件一个新的addList强制它重新渲染,而如果addList是稳定的(因为它是记忆化的),该组件可能能够避免重新渲染。但是是否要存储addList取决于要将其提供给的组件。(更多关于这一点,请参见我对useCallbackhere的回答。

2ul0zpep

2ul0zpep2#

修复了第一个类型错误:

const newItem: listData = { text: item, isDone: false, viewMode: { display: '' }, editMode: { display: 'none' } }
  const newList = [...list, newItem];

相关问题