reactjs - React img src 未从 aws s3 url 显示
问题描述
我有一个对象数组,其中每个对象的属性之一是文件名。然后,我使用该文件名从我编写的 API 端点获取预签名的 AWS S3 url。然后我想映射每个对象并显示有关它的信息,包括显示图像。无论出于何种原因,这都不起作用。大约一半的时间它只是不显示与图像相关的任何内容......不是实际图像,也不是任何“无图像”图标。另一半时间,当它确实工作时,它只会闪烁图像一秒钟,然后恢复为小的“无图像”图标。我不知道为什么这不起作用,因为我让它在另一个不需要映射的组件中工作,而且由于问题并没有始终如一地表现出来,我更加困惑......
这是不起作用的组件的代码:
export const MemeList = () => {
const [state, setState] = useState<State>({
memes: []
});
useEffect(() => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/memes/`)
.then((response) => response.json())
.then((memes) => {
var newMemes = memes.map((meme) => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/images/${meme.file}`)
.then((response) => response.json())
.then((image) => {
meme.image = image;
});
return meme;
});
setState({ memes: newMemes });
console.log(newMemes);
});
}, []);
return (
<>
{(state.memes.length == 0) ? (
<p>Loading...</p>
) : (
<div className="container">
<h2 className="comp-title">Featured Memes</h2>
<div className="featured-memes">
{
state.memes.slice(0,3).map((meme,i) => {
return (
<div id={meme.id} className="meme">
<div className="vote-container">
<Vote className="vote" upvotes={meme.upvotes} category='memes' id={meme.id} upvoters={meme.upvoters} downvoters={meme.downvoters} />
</div>
<Link id={meme.id} to={`/memes/${meme.id}`}>
<div className="meme-container">
<div className="meme-head">
<h2 className="meme-title">{meme.title}</h2>
</div>
<div className="meme-body">
<img className="meme-img" src={meme.image} />
</div>
</div>
</Link>
</div>
)
})
}
</div>
</div>
)}
</>
);
这是工作组件的代码:
useEffect(() => {
setLoading(true);
fetch(`${process.env.REACT_APP_BACKEND_URL}/memes/${memeId}`)
.then((response) => response.json())
.then((meme) => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/images/${meme.file}`)
.then((response) => response.json())
.then((image) => {
setState({ ...state, id: meme.id, title: meme.title, upvotes: meme.upvotes, upvoters: meme.upvoters, downvoters: meme.downvoters, comments: meme.comments, file: image, posterAddress: meme.posterAddress, category: meme.category, stakeWithdrawn: meme.stakeWithdrawn });
})
.then(setLoading(false))
.catch((err) => window.alert(err));
})
.catch((err) => window.alert(err));
}, []);
return (
<>
{(state.file == '') ? (
<p>Loading</p>
) : (
<div className="meme-comp-container">
<div className="meme-comp-vote-container">
<Vote className="vote" upvotes={state.upvotes} category="memes" id={state.id} upvoters={state.upvoters} downvoters={state.downvoters} />
</div>
<div className="meme-comp-meme-container">
<div className="meme-comp-meme-head">
<h2 className="meme-comp-title">{state.title}</h2>
</div>
<div className="meme-comp-meme-body">
<img className="meme-comp-meme-img" src={state.file} />
</div>
</div>
</div>
)}
</>
)
**编辑:**快速更新,所以我想我找到了问题但不知道如何解决它。在 useEffect 钩子中,如果我打印“newMemes”,它会正确显示所有内容,但如果我映射 newMemes 并仅打印它显示未定义的图像属性。
useEffect(() => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/memes/`)
.then((response) => response.json())
.then((memes) => {
var newMemes = memes.map((meme) => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/images/${meme.file}`)
.then((response) => response.json())
.then((image) => {
meme.image = image;
});
return meme;
});
setState({ memes: newMemes });
newMemes.slice(0,3).map((newMeme) => console.log(newMeme.image));
console.log(newMemes);
});
}, []);
给出输出:undefined undefined undefined [0: category: "meme" comments: 0 createdAt: "2021-09-11T23:12:58.956Z" downvoters: [] file: "corp_site_logo_1631401978598.png" id: 11 image: "https: // - - .s3.amazonaws.com/corp_site_logo_1631401978598.png?AWSAccessKeyId= &Expires= &Signature=W% %3D" posterAddress: "0x8a8b5a97978db4a54367d7dcf6a50980990f2373" 58.956Z" 支持者:['0x8a8b5a97978db4a54367d7dcf6a50980990f2373'], 1: ..., 2: ..., ...]
解决方案
如果您比较工作代码和非工作代码,您应该立即注意到差异。在工作代码中,您请求单个 meme 并单独获取其图像,并将状态更新入队。在非工作代码中,您请求多个 meme,单独获取图像,在这些请求可能解决之前将状态更新排队,然后改变状态对象。这就是为什么您会看到与第一个不工作的代码片段不一致的结果。
您可以单独请求每个图像并使用功能状态更新将增强meme
对象添加到状态。
useEffect(() => {
fetch(`${process.env.REACT_APP_BACKEND_URL}/memes/`)
.then((response) => response.json())
.then((memes) => {
memes.forEach(meme =>
fetch(`${process.env.REACT_APP_BACKEND_URL}/images/${meme.file}`)
.then((response) => {
if (!response.ok) throw new Error('response not ok');
return response.json();
})
.then((image) => {
setState(prevState => ({
...prevState,
memes: [
...prevState.memes,
{
...meme,
image,
}
],
}));
})
.catch(error => {
// handle error
})
.finally(() => {
// clear any loading state
});
);
}, []);
推荐阅读
- ios - ASIdentifierManager is not found in iOS12
- javascript - Send data from Client to Client within localhost with ajax
- android - TabItem 标记值为空
- ansible - 将 ansible 功能限制为旧版本?
- java - Spring boot - set dynamic property on creation
- opencv - OpenCV:关于solvePnP的困惑
- javascript - React、Solidity、以太坊:我无法创建正确调用智能合约功能的 React 按钮
- c# - 最大轴 x 图表 c#
- erlang - 如何从受监督的工作进程中触发 Elixir 主管树终止
- html - srcset 属性未从尺寸显示正确的图像