【问题标题】:Conditional rendering does not wait for axios data fetch条件渲染不等待 axios 获取数据
【发布时间】:2021-04-25 03:40:50
【问题描述】:

我要做的是用 axios 获取数据,然后将数据设置为 state。一旦结束,我将加载标志设置为 false 并有条件地渲染一个子组件,我想在其中检索数据数组的第一项的属性。

这是我的自定义钩子代码。我只是获取产品数据并设置数据。

export const useAllProducts = () => {
  // const { showMessage } = useMessage();
  const [loading, setLoading] = useState(false);
  const [products, setProducts] = useState<Array<Product>>([]);

  const getProducts = useCallback(() => {
    setLoading(true);
    axios
      .get<Array<Product>>("http://localhost/api/admin/products")
      .then(res => setProducts(res.data))
      .catch(() =>
        console.log('failed to fetch product data')
      )
      .finally(() => setLoading(false));
  }, []);

  return { getProducts, loading, products };
};

这是我的产品页面。加载完成后,它会以产品数据为道具呈现产品列表组件。

const ProductPage: React.FC = () => {
  const { getProducts, loading, products } = useAllProducts();
  useEffect(() => {
    getProducts();
  }, []);

  return (
    <CommonLayout title="product list">
      {!loading ?
        <ProductList title="product" data={products as Product[]} /> : 'loading'
      }
    </CommonLayout>
  );
}
export default ProductPage;

在此之后,在产品列表组件中,我希望能够像这样访问属性名称。

  const ProductList = <T,>(
  props: React.PropsWithChildren<Props<T>>
) => {
  console.log(props)
  const classes = useStyles();
  Object.keys(props.data[0])

  return (
    <div>
      a
    </div>
  );
}

但是,它给了我如下错误。

未捕获的类型错误:无法将未定义或 null 转换为对象 在 Function.keys () 在 ProductList (app.js:12755) 在 renderWithHooks (app.js:33809) 在 mountIndeterminateComponent (app.js:36488) 在 beginWork (app.js:37602) 在 HTMLUnknownElement.callCallback (app.js:19194) 在 Object.invokeGuardedCallbackDev (app.js:19243) 在 invokeGuardedCallback (app.js:19298) 在 beginWork$1 (app.js:42209) 在 performUnitOfWork (app.js:41160)

我什至先检查了数据的长度,但没有运气。

有没有人知道为什么条件渲染不起作用?

编辑1

这是我在 cmets 之后更改的自定义挂钩代码。逻辑似乎很好..

export const useAllProducts = () => {
  const [loading, setLoading] = useState(true);
  const [products, setProducts] = useState<Array<Product>>([]);

  const getProducts = useCallback(() => {
    axios
      .get<Array<Product>>("http://localhost/api/admin/products")
      .then(res => {
        setProducts(res.data)
        setLoading(false)
      })
      .catch((error) =>
        console.log(error)
      )
  }, []);

  return { getProducts, loading, products };
};

编辑:2

我的简化产品列表组件代码。

const ProductList = <T, >(
  props: React.PropsWithChildren<Props<T>>
) =>{
  console.log(props)
  const classes = useStyles();
  Object.keys(props.data[0])
  //The error is happening here//

【问题讨论】:

  • 不应该是!loading ? &lt;ProductList /&gt; : "loading"吗?
  • 你的条件应该是loading ? "Loading": &lt;ProductList title="product" data={products as Product[]} /&gt; }
  • 我想我知道问题所在,默认的loading 值是false,所以它会抛出该错误,因为创建组件时products 仍然为空,尝试将其设置为@987654331 @像这样const [loading, setLoading] = useState(true);
  • finally 块中删除 setLoading false。如果出现错误,组件仍然会呈现。
  • @Medi 这似乎是正确的模式,无论发生什么——错误或数据,您必须将 loading 设置为 false,因为无论是否有错误都完成了加载。要处理错误,您有 OP 可以在控制台中看到的 catch 块。

标签: javascript reactjs typescript


【解决方案1】:

这行好像有问题

loading 
  ? <ProductList title="product" data={products as Product[]} /> 
  : 'loading'

loading 为真时,您将显示产品列表。应该是另一种方式

loading 
  ? 'loading'
  : <ProductList title="product" data={products as Product[]} />

另外,最好检查一下产品是否有一些有效值

喜欢

loading || !products
  ? 'loading'
  : <ProductList title="product" data={products as Product[]} />

甚至更好,

在您的ProductList 中检查data 是否为空或未定义并向用户显示No product found 的通知。我认为只是更好的用户体验。


好的,这就是问题

Object.keys(props.data[0])

现在,猜猜data = [] 会发生什么? data[0]undefined。它不是一个对象,它是未定义的。

data = []; Object.keys(data[0])
VM633:1 Uncaught TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at <anonymous>:1:19

更好的方法是(假设,实际上,您希望通过迭代来呈现项目)。

data.map(d => console.log(Object.keys(d)))

【讨论】:

  • 感谢您的评论。我尝试了最后一个,它仍然给了我错误 app.js:12755 Uncaught TypeError: Cannot convert undefined or null to object 似乎组件由于某种原因没有等待数据加载。
  • 您需要将 ProductList 中的 props 定义为 {title: string, data: Product[] | null | undefined} 并进行相应处理。这将修复类型错误。既然是本地主机,那它肯定很快。你可以使用 Chrome DevTools 将网络设置为慢 3G,看看网络调用是否正在发生,以及正在返回和渲染什么数据。
  • product 数组始终是真值,即使数组为空。你检查数组的长度。
  • @Medi 哦,对。接得好。默认为空数组。感谢您指出这一点。
猜你喜欢
  • 2021-08-31
  • 2018-09-03
  • 1970-01-01
  • 2020-10-01
  • 1970-01-01
  • 2020-08-19
  • 2019-05-30
  • 1970-01-01
相关资源
最近更新 更多