开发者问题收集

React 上下文抛出 TypeError:对象不可迭代(无法读取属性 Symbol(Symbol.iterator))

2022-09-03
187

我收到错误:

TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))

每当我尝试从 useContext 管理状态时。这里的想法是允许在页面加载时在 [] 处初始化“令牌”,然后在 TokenListBox 组件中设置时,随后在 TokenProviderContext 中更新它。

TokenProviderContext.tsx:

const TokenProviderContext = React.createContext<any>([]);

export const TokenProvider = ({
  children,
}: {
  children:
    | ReactElement<React.ReactNode, string | JSXElementConstructor<unknown>>[]
    | ReactElement<React.ReactNode, string | JSXElementConstructor<unknown>>;
}) => {
  const [selectedTokens, setSelectedTokens] = useState<IToken[]>(sampleTokenList);

  const contextValue = useMemo(
    () => ({
      selectedTokens,
      setSelectedTokens,
    }),
    [selectedTokens, setSelectedTokens],
  );

  return <TokenProviderContext.Provider value={contextValue}>{children}</TokenProviderContext.Provider>;
};

export const useTokenProvider = () => useContext(TokenProviderContext);

TokenListBox.tsx:

export default function TokenListBox({ tokenList }: { tokenList: IToken[] }) {
  const [selectedTokens, setSelectedTokens] = useTokenProvider();

  useEffect(() => {
    if (!selectedTokens) {
      setSelectedTokens([]);
    }
  }, [selectedTokens, setSelectedTokens]);

  return (
    <Listbox value={selectedTokens} onChange={setSelectedTokens} multiple>
      {({ open }) => (
        <>
          <div className="relative mt-1">
            <Listbox.Button
              className="relative w-full cursor-default rounded-md border border-gray-300 bg-white
            py-2 pl-3 pr-10 text-left shadow-sm focus:border-sky-500 focus:outline-none focus:ring-1 focus:ring-sky-500
            sm:text-sm"
            >
              <span className="flex items-center">
                <span className="block truncate">Select Tokens</span>
              </span>
              <span className="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2">
                <ChevronUpDownIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
              </span>
            </Listbox.Button>
            <Transition
              show={open}
              as={Fragment}
              leave="transition ease-in duration-100"
              leaveFrom="opacity-100"
              leaveTo="opacity-0"
            >
              {tokenList.length > 0 && (
                <Listbox.Options
                  className="absolute z-10 mt-1 max-h-56 w-full overflow-auto rounded-md bg-white py-1
              text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
                >
                  {tokenList.map((token) => (
                    <Listbox.Option
                      key={token.symbol}
                      className={({ active }) =>
                        classNames(
                          active ? 'text-white bg-sky-600' : 'text-gray-900',
                          'relative cursor-default select-none py-2 pl-3 pr-9',
                        )
                      }
                      value={token.name}
                    >
                      {({ selected, active }) => (
                        <>
                          <div className="flex items-center">
                            <img src={token.iconSrcUrl} alt="" className="h-6 w-6 flex-shrink-0 rounded-full" />
                            <span
                              className={classNames(selected ? 'font-semibold' : 'font-normal', 'ml-3 block truncate')}
                            >
                              {token.name}
                            </span>
                          </div>
                          {selected ? (
                            <span
                              className={classNames(
                                active ? 'text-white' : 'text-sky-600',
                                'absolute inset-y-0 right-0 flex items-center pr-4',
                              )}
                            >
                              <CheckIcon className="h-5 w-5" aria-hidden="true" />
                            </span>
                          ) : null}
                        </>
                      )}
                    </Listbox.Option>
                  ))}
                </Listbox.Options>
              )}
            </Transition>
          </div>
        </>
      )}
    </Listbox>
  );
}
1个回答

当您调用 useTokenProvider() 时,您将获得结果 contextValue ,它是一个对象而不是数组,因此会出现错误。

假设 TokenListBox 包装在 TokenProvider 中,这将起作用:

const {selectedTokens, setSelectedTokens} = useTokenProvider();
Youssouf Oumar
2022-09-03