【发布时间】:2022-01-09 21:31:42
【问题描述】:
无论出于何种原因,我的故事书设置都不喜欢对象导入。每次在对象上导入它的 undefined 并给我一个 TypeError。
对象作为 React 子级无效(发现:TypeError: Cannot read properties of undefined (reading 'news'))。如果您打算渲染一组子项,请改用数组。
我正在尝试导入 api.ts 的文件
interface Api {
news: {
getNews: Function;
};
}
const api: Api = {
news: {
getNews: async (
pageIndex?: number,
pageSize?: number,
featuredArticleId?: string,
newsCategoryId?: string,
type?: string,
tag?: string,
) => {
const { data }: AxiosResponse = await Axios.get(`${config.apiUrl}/news/listing`, {
params: {
newsCategoryId,
pageIndex,
pageSize,
type,
featuredArticleId,
tag,
},
});
return data;
},
},
};
export default api;
React 组件看起来像这样。当我注销 api 时,它总是未定义。
import * as React from 'react';
import { useEffect, useState, useRef } from 'react';
import Reveal from 'react-reveal/Reveal';
import { v4 as uuidv4 } from 'uuid';
import {
Loader,
Pagination,
Dropdown,
SectionHeading,
} from '../Common';
import { Container } from '../Helpers/Grid';
import FeaturedArticleCard from '../FeaturedNewsCard';
import NewsCard from '../NewsCard';
import NewsListProps from './type';
import NewsCardProps from '../NewsCard/type';
import getCurrentPage from '../Common/Pagination/getCurrentPage';
import api from '../../core/api/models';
import { NewsListApiResponse, Pagination as PaginationType } from '../../core/typings/api';
import { scrollIntoView, insertUrlParam } from '../../utilities/browser';
import './styles.scss';
console.log('api -> ', api);
interface FilterOption {
displayText: string;
value: string;
selectedValue?: boolean;
}
// May need to come from the languages array
const defaultSelectedValue: string = 'all';
const NewsList = ({
categories,
featuredArticle,
newsCategoryId,
title,
tag,
noResultsText,
}: NewsListProps) => {
const newsListItemsContainer = useRef<HTMLUListElement>(null);
const [pageSize] = useState<number>(12);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [selectedFilter, setSelectedFilter] = useState<FilterOption>(categories[0]);
const [items, setItems] = useState<NewsCardProps[]>();
const [apiError, setApiError] = useState<string>();
const [pagination, setPagination] = useState<PaginationType>();
/**
* Calls to news list api endpoint and updates state
* accordingly
* @param page
*/
const fetchNews = async (page: number) => {
const featuredArticleId = featuredArticle ? featuredArticle.id : undefined;
const type = selectedFilter?.value !== defaultSelectedValue ? selectedFilter.value : undefined;
setIsLoading(true);
try {
const data: NewsListApiResponse = await api.news.getNews(
page,
pageSize,
featuredArticleId,
newsCategoryId,
type,
tag,
);
setItems(data.items);
setPagination(data.pagination);
setIsLoading(false);
} catch (error) {
setApiError(error as string);
}
};
/**
* Pagination change action
* @param page
*/
const handlePage = (page: number) => {
fetchNews(page);
scrollIntoView(
newsListItemsContainer?.current as HTMLUListElement,
'smooth',
);
};
/**
* Updates the selected filter item from the jump list action
* @param option
*/
const filterByCategory = async (option: FilterOption) => {
setSelectedFilter(option);
};
/**
* Observes the selectedFilter state. If the state changes
* and the value is not the default value it will call the
* fetchNews method.
*/
useEffect(() => {
if (selectedFilter) {
fetchNews(1);
insertUrlParam('page', '1');
}
}, [selectedFilter]);
/**
* Inital actions on componentDidMount
*/
useEffect(() => {
// fetchNews(Number(getCurrentPage()));
// We need to listen on popstate
window.addEventListener('popstate', () => {
fetchNews(Number(getCurrentPage()));
}, false);
}, []);
return (
<Container>
<>
{featuredArticle && (
<div className="news-list-feature">
<div className="news-list-feature__label">
<h3>Featured</h3>
</div>
<Reveal effect="shortFadeInUp">
<FeaturedArticleCard {...featuredArticle} />
</Reveal>
</div>
)}
<section className="news-list">
{Boolean(!isLoading && items?.length) && (
<div className="news-list__title">
<SectionHeading text={title} />
</div>
)}
<div className="news-list__container">
{categories && (
<div className="news-list__filters">
<Dropdown
items={categories}
action={filterByCategory}
selectedValue={selectedFilter.value}
icon="icon-plus"
position="right"
/>
</div>
)}
{apiError && (
<div className="news-list__api-error">
<h3>{apiError}</h3>
</div>
)}
{Boolean(!items?.length && !isLoading) && (
<div className="news-list__no-results">
<h3>{noResultsText}</h3>
</div>
)}
{isLoading && (
<div className="news-list__loader">
<Loader />
</div>
)}
<ul ref={newsListItemsContainer} className="news-list__items">
{Boolean(!isLoading && items?.length) && (
<>
{items?.map((item, index) => (
<Reveal effect="shortFadeInUp" delay={index * 50}>
<li key={uuidv4()} className="news-list__item">
<NewsCard key={uuidv4()} {...item} />
</li>
</Reveal>
))}
</>
)}
</ul>
{Boolean(pagination && items?.length) && (
<nav className="news-list__pagination">
<Pagination
totalItems={pagination?.totalItems as number}
currentPage={pagination?.currentPage as number}
itemsPerPage={pagination?.itemsPerPage as number}
handleClick={handlePage}
/>
</nav>
)}
</div>
</section>
</>
</Container>
);
};
export default NewsList;
我猜这可能与我设置项目的方式有关?不知道发生了什么以及为什么,我只是在网上发现了死胡同。
【问题讨论】:
-
你能展示一下你是如何在组件中使用它的吗?你在哪里访问
news? -
setApiError(error as string);不投射时错误是什么样子的? -
错误是否可能实际上是您尝试在组件中呈现为字符串的对象?
-
不敢相信这是我什至没有意识到的问题。我整天都在看这个,仅此而已。非常感谢
-
其实我在说谎 api 仍然未定义但现在没有出现 TypeError
标签: javascript reactjs typescript storybook