gpt4 book ai didi

javascript - 当 Redux 状态改变时,React 不会重新渲染

转载 作者:行者123 更新时间:2023-11-30 13:52:14 25 4
gpt4 key购买 nike

在 React 应用程序中,我将从 Redux 存储中获取的一些数据映射到某个组件

{this.props.team && this.props.team.map((value: User, index: number) =>
(<Card key={index} className="team-card">
<CardMedia style={{
backgroundImage: `url(${value.photoURL})`
}} />
<Typography use={"headline4"}>{value.displayName}</Typography>
<Typography use={"body1"}>{value.description}</Typography>
<CardActions>
<CardActionButtons>
{/* TODO: Add the ability to go to About to a specific team member card */}
<CardActionButton>Vezi profilul</CardActionButton>
</CardActionButtons>
</CardActions>
</Card>)
)}

这里 team 是从 redux Store 映射而来的 prop。当用户打开应用程序时,Redux 存储中的数据将从数据库中获取。这是可行的,因为我已经记录了 team Prop 的更改并且它实际上按预期更新。

问题是,即使在 prop 更新后(可能在初始渲染后一秒钟发生),应用程序也不会重新渲染以反射(reflect)此 prop 更改。但是,如果之后这个组件被卸载并重新安装,它就会正确呈现。此外,在卸载和重新安装之间,redux 存储不会更新,并且在安装生命周期中没有任何反应。

有谁知道是什么导致了这种行为?提前致谢!

更新:

这是完整的组件(它使用 Typescript)

import React from "react"
import { Article } from "../../models/Article";
import Carousel, { CarouselItem } from "../Carousel/Carousel";


import "./Homescreen.scss";
import { connect } from "react-redux";
import AppState from "../../store/AppState";
import { Typography, Card, CardMedia, CardActionButton, CardActions, CardActionButtons } from "rmwc"
import User from "../../models/User";

import ArticleCompact from "../Article/ArticleCompact/ArticleCompact";
import Navbar from "../Navbar/Navbar";

class Homescreen extends React.Component<HomescreenProps, {}>{

constructor(props: Readonly<HomescreenProps>) {
super(props);

}

render() {
return (
<main>
<Navbar></Navbar>
<div id="container">
<div id="content">
<Carousel className="homescreen-carousel" items={this.props.carouselItems} speed={5}></Carousel>
{this.props.recentArticles.length !== 0 && (<section id="homescreen-recent-articles">
<Typography use={"headline2"} className="homescreen-head">Recente</Typography>
<hr className="homescreen-hr" />
{this.props.recentArticles[0] && (
<ArticleCompact URL={"/article/" + this.props.recentArticles[0].url} image={this.props.recentArticles[0].coverURL}
text={this.props.recentArticles[0].shortVersion} title={this.props.recentArticles[0].title}
type={"left-to-right"}
/>)}
{this.props.recentArticles[1] && (<ArticleCompact URL={"/article/" + this.props.recentArticles[1].url} image={this.props.recentArticles[1].coverURL}
text={this.props.recentArticles[1].shortVersion} title={this.props.recentArticles[1].title}
type={"right-to-left"}
/>)}
</section>)}
<section id="homescreen-team">
<Typography use={"headline2"} className="homescreen-head">Echipa</Typography>
<hr className="homescreen-hr" />
<div id="team-cards">
{this.props.team && this.props.team.map((value: User, index: number) =>
(<Card key={index} className="team-card">
<CardMedia style={{
backgroundImage: `url(${value.photoURL})`
}} />
<Typography use={"headline4"}>{value.displayName}</Typography>
<Typography use={"body1"}>{value.description}</Typography>
<CardActions>
<CardActionButtons>
{/* TODO: Add the ability to go to About to a specific team member card */}
<CardActionButton>Vezi profilul</CardActionButton>
</CardActionButtons>
</CardActions>
</Card>)
)}
</div>
</section>
</div>
</div>
</main>
)
}
}



function mapStateToProps(state: Readonly<AppState>) {
const items: CarouselItem[] = [] as CarouselItem[];
const articles: Article[] = [];
if (state.articles.featured.length !== 0)
state.articles.featured.map((item: Article) => {
return {
image: item.coverURL,
title: item.title,
path: "/article/"+item.url
}
}
).forEach((value: CarouselItem) => {
items.push(value);
})

//Map the first 4 recent articles to CarouselItems and push them to an array
state.articles.recent.map(async (item: Article) => (
{
image: URL.createObjectURL(await fetch(item.coverURL).then(res => res.blob())),
title: item.title,
path: "/article/"+item.url
})
).forEach(async (value, index) => {
if (index < 4)
items.push(await value);
});

//Map the last 2 recent articles to props
for (let [index, article] of state.articles.recent.entries()) {
if (index >= 4)
articles.push(article)
}

return {
carouselItems: items,
recentArticles: articles,
team: state.metadata.team
}
}

export default connect(mapStateToProps)(Homescreen);

这里还有负责更新该存储属性的 reducer

export default function userReducer(state: Readonly<MetadataState> | undefined = initialAppState.metadata, action: MetadataActions): MetadataState {
switch (action.type) {
case 'TEAM_RECIEVED': return { ...state, team: action.payload };
default: return state;
}
}

更新#2:

以下是解除 TEAM_RECIEVED

的操作
export function retrieveTeam() {
return async (dispatch: Dispatch) => {

const team = await getTeam_firestore();
const mappedTeam: User[] = [];
team.forEach(async (val: User, index: number) => mappedTeam.push({
...val,
photoURL: val.photoURL !== null ? URL.createObjectURL(await fetch(val.photoURL!!).then(res => res.blob())) : null
}));
console.log('Got team')

return dispatch({
type: 'TEAM_RECIEVED',
payload: mappedTeam
})
}
}

最佳答案

您的异步操作有问题。特别是这段代码:

team.forEach(async (val: User, index: number) => mappedTeam.push({
...val,
photoURL: val.photoURL !== null ? URL.createObjectURL(await
fetch(val.photoURL!!).then(res => res.blob())) : null
}));

将在未来某个时间异步改变任何操作之外的存储状态。这是不允许的。试试这个版本。

export function retrieveTeam() {
return async (dispatch: Dispatch) => {

const team = await getTeam_firestore();
const mappedTeam: User[] = await Promise.all(team.map(
async (val: User, index: number) => {
const result = {...val};
if (result.photoURL !== null) {
const response = await fetch(result.photoURL);
const blob = await response.blob();
result.photoURL = URL.createObjectURL(blob);
}
return result;
}));

console.log('Got team')

return dispatch({
type: 'TEAM_RECIEVED',
payload: mappedTeam
})
}
}

此版本在分派(dispatch) TEAM_RECIEVED 操作之前等待异步获取。

更多解释:

array.foreach(async function) 只会对一堆异步工作进行排队,但 foreach 会立即返回。您需要等待所有异步工作。所以你不能使用 array.foreach()。解决方案是以下两种模式之一:

假设你有这个方法:

async function getValWithPhoto(val) {
const result = {...val};
if (result.photoURL !== null) {
const response = await fetch(result.photoURL);
const blob = await response.blob();
result.photoURL = URL.createObjectURL(blob);
}
return result;
}

模式 1 - 按顺序运行每个异步提取(一次一个):

const mappedTeam = [];
for (const val of team) {
const mappedVal = await getValWithPhoto(val);
mappedTeam.push(mappedVal);
}

return dispatch(...);

模式 2 - 并行(同时)运行所有获取作业(我在上面的回答中所做的):

const arrayOfPromises = team.map(val => getValWithPhoto(val));
// Use Promise.all() to turn the array of promises into a single
// promise: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
const promise = Promise.all(arrayOfPromises);
// now await that promise, which will return array of results
const mappedTeam = await promise;
return dispatch(...);

关于javascript - 当 Redux 状态改变时,React 不会重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58015922/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com