为什么我的组件基于 redux 的 props 没有更新?



在一个将数据存储在redux存储和firebase firestore中的react原生应用程序中,我有一个onSnapshot侦听器,它可以侦听集合。在这个集合中的每个文档中,都有一个具有几个属性的对象,这些属性的值会随着时间的推移而变化。理想情况下,当这些对象属性值中的一个发生更改时,应该反映在redux存储中,从而反映在UI中。问题是,当其中一个值发生变化时,redux存储不会更新。

监听器:

export const onAgendaChange = (uid, role, dispatch) => {
let query;
if (role == 'A') {
query = 'a.uid';
} else {
query = 'b.uid';
}
console.log('(actions/agenda) Firestore Read: getAgenda()');
return firebase
.firestore()
.collection('events')
.where(query, '==', uid)
.orderBy('date')
.onSnapshot((querySnapshot) => {
const agenda = []
querySnapshot.docChanges().forEach(change => {
console.log(`change: ${change.type}`) // does not log anything
})
querySnapshot.forEach((doc) => {
let event = doc.data();
event.id = doc.id;
agenda.push(event);
dispatch({ type: types.LOAD_AGENDA_SUCCESS, payload: agenda });
});
});
};

减速器:

const INITIAL_STATE = {
loading: false,
events: []
};
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case types.LOAD_AGENDA:
return {
...state,
loading: true
};
case types.LOAD_AGENDA_SUCCESS:
return {
loading: false,
events: action.payload
};
default:
return {
...state
};
}
};

使用此数据的屏幕组件:

<View style={styles.container}>
<FlatList
data={this.props.events}
extraData={this.props}
keyExtractor={(item) => {
return (
item.toString() +
new Date().getTime().toString() +
Math.floor(Math.random() * Math.floor(new Date().getTime())).toString()
);
}}
renderItem={({ item, index }) => {
const title = this.props.role == 'A' ? item.b.legalName : item.a.legalName;
const participantCheckInStatus =
this.props.role == 'A' ? item.checkedIn.b : item.checkedIn.a;
const currentUserCheckInStatus =
this.props.role == 'A' ? item.checkedIn.a : item.checkedIn.b;
console.log("agenda type B: " + item.checkedIn.b + " agenda type A: " + item.checkedIn.a)
return (
<Components.AgendaItem
title={title}
participant={participantCheckInStatus}
checkedIn={currentUserCheckInStatus}
navigation={this.props.navigation}
evnt={item}
/>
);
}}
/>
</View>

该集合中的文档结构类似于:

{
exampleMap: { a: false, b: false },
string: '',
string: '',
map: { ... },
map: { ... }
}

其他注意事项:

  • 无论文档是通过操作还是从firebase控制台更新,文档都会在firestore中成功更新
  • 即使刷新了react本机应用程序,使用有问题数据的组件也不会更新
  • 我有另一个文件集,里面也有地图。当更改其他集合的映射中的值时,使用此数据的组件将正确更新。它们具有相似的还原器,两个还原器都是持久化的,侦听器是相同的
  • 我还在我提到的这些相关减速器上使用redux persistent,包括工作减速器和非工作减速器
  • im使用redux thunk

PECULIAR观察结果:

  • 组件正确接收道具更新的唯一时间是应用程序安装是否新鲜,这意味着应用程序已被删除并新鲜安装在模拟器上。任何后续运行,道具数据都不会更新

我使用这个redux存储在父组件和子组件中确认,当我在firebase控制台中更改值时,文档的exampleMap子属性值不会在redux中更改。所以我到处玩FlatList的extraData道具,但没有用。

不管怎样,你有没有想过如何将这些更改添加到redux商店?

这是给您带来问题的部分:


.onSnapshot((querySnapshot) => {
const agenda = []
querySnapshot.docChanges().forEach(change => {
console.log(`change: ${change.type}`) // does not log anything
})
querySnapshot.forEach((doc) => {
let event = doc.data();
event.id = doc.id;
agenda.push(event);
dispatch({ type: types.LOAD_AGENDA_SUCCESS, payload: agenda });
});
});

问题是,您正在为后续调度重新使用相同的agenda数组——在两者之间对其进行修改。

在您的减速器中


case types.LOAD_AGENDA_SUCCESS:
return {
loading: false,
events: action.payload
}

你只是在为这个对象设置事件——这意味着当react redux比较旧的events和新的events时,它是对同一对象的引用。RR看不出有什么不同。

要解决此问题,您可以先复制该阵列,然后再将其保存到您的商店:


case types.LOAD_AGENDA_SUCCESS:
return {
loading: false,
events: [...action.payload]
}

您需要在减速器中进行以下更改:

case types.LOAD_AGENDA_SUCCESS:
return { ...state, loading: false, events: [...action.payload] };

由于您的屏幕组件将检查events道具的引用,以确定是否重新渲染,因此您可以通过使用如上所示的排列运算符更改引用来解决此问题。

此外,您应该将dispatch调用转移到forEach循环之外,以便agenda数组只与其中的所有项目一起发送到reducer一次,而不是针对每个项目一次又一次地发送:

querySnapshot.forEach((doc) => {
let event = doc.data();
event.id = doc.id;
agenda.push(event);
});
dispatch({ type: types.LOAD_AGENDA_SUCCESS, payload: agenda });

最新更新