【问题标题】:function Component receive props but doesn't render it功能组件接收道具但不渲染它
【发布时间】:2020-09-09 14:50:53
【问题描述】:

情况:

首先,我从数据库中获取 imgs 列表:

{imgs:
    [
        {_id: '...',img:'***.png'},
        ...,
    ]
}

然后,使用 ali-oss-hook 签名 img.src,结果如下:

{imgs:
    [
        {_id:'...', img: '***.png', src: 'signatured-http-address'}
        ...,
    ]
}

然后,将imgs传递给PictureList组件:

<PictureList imgs={images}

PictureList收到新的道具,但没有渲染它

const PictureList = ({ imgs }) => {
 return (
 <ul>
 {imgs.map((i) => (
   <img key={i._id} src={i.src} alt="pic" />
 ))}
 </ul>
 );
}
export default PictureList

代码

图片.js

import React, {useEffect, useState, useRef } from 'react'
import { useAlioss } from '../../hooks/oss-hook'
import PictureList from '../../components/PictureList'

import './style.less'

const Pictures = () => {
  const [loading, setLoading] = useState(true)
  const [signatured, setSignatured] = useState(false)
  const [results, setResults] = useState()
  const [images, setImages] = useState([])

  const { allowUrl } = useAlioss()
 
  const resultsDoSetRef = useRef(false)
  
  async function getImages() {
    try {
      const dbResponse = await fetch(
        `${process.env.REACT_APP_BACKEND_URL}/upload/images`
      );

      const resu = await dbResponse.json();

      setResults(resu)
      resultsDoSetRef.current = true

    } catch (e) {
      console.log("get images failed")
    } finally {
      setLoading(false)
      console.log("get images done!")
    }
  }

  useEffect(() => {
    getImages();
  }, [])
  
  async function signatureUrl(raw) {
    setSignatured(false)
    try {
      let tempImgs = []

      raw.imgs.forEach((r) => {
        allowUrl(r.img).then((res) => {
          r.img = res;
          tempImgs.push(r)
        });
      });

      setImages(tempImgs);
    } catch (e) {
      console.log("signature failed",e)
    } finally {
      setSignatured(true)
      console.log("signature done!")
    }
  }

  useEffect(() => {
    if (resultsDoSetRef.current) {
      resultsDoSetRef.current = false
      signatureUrl(results);
    }
  },[results])
  
  return (
    <div className="picture">
      {loading ? <h1>Loading</h1> : <PictureList imgs={images} />}
    </div>
  );
};

export default Pictures

图片列表.js

const PictureList = ({ imgs }) => {
 return (
 <ul>
 {imgs.map((i) => (
   <img key={i._id} src={i.src} alt="pic" />
 ))}
 </ul>
 );
}
export default PictureList

chrome react devTool component shows props

chrome devTool element shows empty PictureList

chrome devTool react 组件 显示正确的 props,但 PictureList 组件仍为空&lt;ul&gt;&lt;/ul&gt;

哪一部分错了?

【问题讨论】:

  • &lt;PictureList /&gt; 组件看起来没问题,控制台有错误吗?
  • @norbitrial 控制台没有错误!

标签: reactjs async-await react-hooks react-props


【解决方案1】:

查看 PictureList.js,您正在接收“imgs”作为函数的参数,这与您传入的属性不同

<PictureList imgs={images}

这个“imgs”其实是一个拥有imgs属性的对象,所以你的代码会变成:

const PictureList = ({ imgs }) => {
 return (
 <ul>
 {imgs.imgs.map((i) => (
   <img key={i._id} src={i.src} alt="pic" />
 ))}
 </ul>
 );
}
export default PictureList

P.S : 只是一个建议,一般道具(或类似的描述)被用作参数参数,所以你的代码将是这样的:

const PictureList = ({ props }) => {
     return (
     <ul>
     {props.imgs.map((i) => (
       <img key={i._id} src={i.src} alt="pic" />
     ))}
     </ul>
     );
    }
    export default PictureList

【讨论】:

  • const PictureList = props =&gt; { console.log(props.imgs) return (&lt;ul&gt;{props.imgs.map((i) =&gt; (...);}&lt;/ul&gt;。我尝试传递一个通用的props 作为参数,并添加一个console.logimgs 如愿打印在控制台上,甚至打印两次:[] 0:{ _id: "...", img: "....jpg", src: "..."} 1: {_id: "...", img: "....jpg", src: "..."} 2: {_id: "...", img: "***.jpg", src: "..."} length: 3 __proto__: Array(0) PS:我更改了图片:allowUrl(r.img).then((res) =&gt; { r.src = res; tempImgs.push(r) }) 在 img 对象中添加 src
【解决方案2】:

Picture --signatureUrl() 方法中,raw.imgs.forEach() 返回一堆 promises,这些promise 不能一次全部解决。

setImages(tempImgs)时,useState hook中的images先接收一个空数组,然后@987654323时将新图像推送到images数组@ 返回 promise 解析一个新的图像项

所以,我们必须等待所有allowUrl(r.img) 承诺解决,然后setImages(tempImgs)

function signatureUrl(raw) {
    const tasks = raw.imgs.map(i => allowUrl(i.img))
    Promise.all(tasks).then(values => {
      let resultImgs = raw.imgs.map((t, index) => ({ ...t, src: values[index] }));

      setImages(resultImgs)
    })
  }

PS:解决方案确实有效,但所有分析都可能有误,仅供参考。

【讨论】:

    猜你喜欢
    • 2019-07-18
    • 2020-10-21
    • 2016-05-06
    • 2021-08-23
    • 2023-02-15
    • 2021-12-22
    • 2020-11-16
    • 2019-08-22
    • 1970-01-01
    相关资源
    最近更新 更多