redux useSelector解构与联合类型?

agxfikkp  于 2023-06-23  发布在  其他
关注(0)|答案(1)|浏览(103)

最近,我试图重新考虑我在应用程序中使用的状态结构,但我遇到了一些困难,不知道如何继续下去。
首先,我使用了下面的redux状态结构:

type State = {
  loading: boolean
  loaded: boolean
  items: Array<Item>
  categories: Array<Category>
}

const initialState: State = {
  loading: false,
  loaded: false,
  items: [],
  categories: [],
}

它简单且易于与选择器一起使用,并且因为itemscategories的类型始终保持相同,因此无需担心未定义或强制转换类型。但是我需要添加一些额外的属性,我只需要几次和干燥来为每个redux动作创建一个单独的类型,现在我有了这个:

type RequestItems = {
  category: Category;
  items: Array<Item>;
  totalCountFromServer: number;
}

export type RequestItem = {
  item: Item;
}

export type RequestCategories = {
  categories: Array<Category>
}

type RequestContent =
  | RequestItem
  | RequestItems
  | RequestCategories

type State = {
  loading: boolean;
  loaded: boolean;
  content: RequestContent | undefined
}

这种结构不那么冗余,但我不确定useSelector是否可以确定extact类型,或者是否有比这更好的方法来使用它:
我认为在这里使用状态钩子有点多余,但是我可以检查内容幻灯片是否“欠精确”,如果是,则返回“404”。

const { content, loading, loaded } = useSelector(state => ({
    content: state.suply.content,
    loading: state.suply.loading,
    loaded: state.suply.loaded,
  }))

  const [items, setItems] = useState<Items[]>([])
  const [category, setCategory] = useState<Category>(Category.emptyObject)
  const [totalCountFromServer, setTotalCountFromServer] = useState<number>()

  useEffect(() => {
    if (content) {
      setItems((content as RequestItems).items)
      setCategory((content as RequestItems).category)
      setTotalCountFromServer((content as RequestItems).totalCountFromServer)
    }
  }, [content])

或者这个这里我得到TypeError,因为选择器无法读取undefined的属性(阅读'items','category','totalCountFromServer')

const { content, loading, loaded } = useSelector(state => ({
    items: (state.suply.content as RequestItems).items,
    category: (state.suply.content as RequestItems).category,
    totalCountFromServer: (state.suply.content as RequestItems).totalCountFromServer,
    loading: state.suply.loading,
    loaded: state.suply.loaded,
  }))

或者像这样使用解构。它工作得很好,但我读到here,使用选择器的析构是错误的方法

const { content, loading, loaded } = useSelector(state => ({
    content: state.suply.content,
    loading: state.suply.loading,
    loaded: state.suply.loaded,
  }))

  const {items, category, totalCountFromServer } = (content as RequestItems);

那么,有没有更好的方法来使用带有Union Type内容的状态,或者我最好使用我的原始结构?

xyhw6mcr

xyhw6mcr1#

遵循“定义类型化挂钩”文档。创建useDispatchuseSelector钩子的类型化版本。
使用歧视工会
例如

import { useSelector } from "react-redux";
import { useEffect } from "react";
import type { TypedUseSelectorHook } from "react-redux";

type Category = any;
type Item = any;

type RequestItems = {
  kind: "RequestItems";
  category: Category;
  items: Array<Item>;
  totalCountFromServer: number;
};

type RequestItem = {
  kind: "RequestItem";
  item: Item;
};

type RequestCategories = {
  kind: "RequestCategories";
  categories: Array<Category>;
};

type RequestContent = RequestItem | RequestItems | RequestCategories;

type State = {
  loading: boolean;
  loaded: boolean;
  content: RequestContent | undefined;
};

const useAppSelector: TypedUseSelectorHook<State> = useSelector;

const useHook = () => {
  const { content, loading, loaded } = useAppSelector((state) => ({
    content: state.content,
    loading: state.loading,
    loaded: state.loaded
  }));

  useEffect(() => {
    if (content?.kind === "RequestItems") {
      // content is RequestItems
    }
  }, [content]);
};

codesandbox

相关问题