Реагируйте на собственный плоский список, не воспроизводящий Redux - PullRequest
0 голосов
/ 24 октября 2019

Мой FlatList не обновляется при смене реквизита, который я передаю. Каждый раз, когда я отправляю сообщение, я увеличиваю количество непрочитанных сообщений, как в базе данных Firebase, так и в своем редукционном магазине. Я удостоверился, чтобы включить ключевой экстрактор и дополнительные данные, но ни один не помогает. Единственное, что изменяет количество непрочитанных сообщений - это перезагрузка устройства. Как мне убедиться, что flatList обновляется с MapStateToProps. Я удостоверился, что создал новый объект с помощью Object.Assign:

action:

export const sendMessage = (
  message,
  currentChannel,
  channelType,
  messageType
) => {
  return dispatch => {
    dispatch(chatMessageLoading());
    const currentUserID = firebaseService.auth().currentUser.uid;
    let createdAt = firebase.database.ServerValue.TIMESTAMP;
    let chatMessage = {
      text: message,
      createdAt: createdAt,
      userId: currentUserID,
      messageType: messageType
    };


    FIREBASE_REF_MESSAGES.child(channelType)
      .child(currentChannel)
      .push(chatMessage, error => {
        if (error) {
          dispatch(chatMessageError(error.message));
        } else {
          dispatch(chatMessageSuccess());
        }
      });

    const UNREAD_MESSAGES = FIREBASE_REF_UNREAD.child(channelType)
      .child(currentChannel).child('users')

    UNREAD_MESSAGES.once("value")
      .then(snapshot => {
        snapshot.forEach(user => {
          let userKey = user.key;
          // update unread messages count
          if (userKey !== currentUserID) {
            UNREAD_MESSAGES.child(userKey).transaction(function (unreadMessages) {
              if (unreadMessages === null) {
                dispatch(unreadMessageCount(currentChannel, 1))
                return 1;
              } else {
                alert(unreadMessages)
                dispatch(unreadMessageCount(currentChannel, unreadMessages + 1))
                return unreadMessages + 1;
              }
            });
          } else {
            UNREAD_MESSAGES.child(userKey).transaction(function () {
              dispatch(unreadMessageCount(currentChannel, 0))
              return 0;
            });
          }
        }
        )
      })
  };
};

export const getUserPublicChannels = () => {
  return (dispatch, state) => {
    dispatch(loadPublicChannels());
    let currentUserID = firebaseService.auth().currentUser.uid;
    // get all mountains within distance specified
    let mountainsInRange = state().session.mountainsInRange;
    // get the user selected mountain
    let selectedMountain = state().session.selectedMountain;

    // see if the selected mountain is in range to add on additional channels
    let currentMountain;
    mountainsInRange
      ? (currentMountain =
        mountainsInRange.filter(mountain => mountain.id === selectedMountain)
          .length === 1
          ? true
          : false)
      : (currentMountain = false);

    // mountain public channels (don't need to be within distance)
    let currentMountainPublicChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
      "Public"
    )
      .child(`${selectedMountain}`)
      .child("Public");

    // mountain private channels- only can see if within range
    let currentMountainPrivateChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
      "Public"
    )
      .child(`${selectedMountain}`)
      .child("Private");

    // get public channels
    return currentMountainPublicChannelsRef
      .orderByChild("key")
      .once("value")
      .then(snapshot => {
        let publicChannelsToDownload = [];

        snapshot.forEach(channelSnapshot => {
          let channelId = channelSnapshot.key;
          let channelInfo = channelSnapshot.val();
          // add the channel ID to the download list

          const UNREAD_MESSAGES = FIREBASE_REF_UNREAD.child("Public")
            .child(channelId).child('users').child(currentUserID)
          UNREAD_MESSAGES.on("value",snapshot => {
              if (snapshot.val() === null) {
                // get number of messages in thread if haven't opened
                dispatch(unreadMessageCount(channelId, 0));
              } else {
                dispatch(unreadMessageCount(channelId, snapshot.val()));
              }
            }
            )
          publicChannelsToDownload.push({ id: channelId, info: channelInfo });
        });

        // flag whether you can check in or not
        if (currentMountain) {
          dispatch(checkInAvailable());
        } else {
          dispatch(checkInNotAvailable());
        }

        // if mountain exists then get private channels/ if in range
        if (currentMountain) {
          currentMountainPrivateChannelsRef
            .orderByChild("key")
            .on("value", snapshot => {
              snapshot.forEach(channelSnapshot => {
                let channelId = channelSnapshot.key;
                let channelInfo = channelSnapshot.val();


                const UNREAD_MESSAGES = FIREBASE_REF_UNREAD.child("Public")
                  .child(channelId).child('users').child(currentUserID)
                UNREAD_MESSAGES.on("value",
                  snapshot => {
                    if (snapshot.val() === null) {
                      // get number of messages in thread if haven't opened
                      dispatch(unreadMessageCount(channelId, 0));
                    } else {
                     dispatch(unreadMessageCount(channelId, snapshot.val()));
                    }
                  }
                  )
                publicChannelsToDownload.push({ id: channelId, info: channelInfo });
              });
            });
        }
        return publicChannelsToDownload;
      })

      .then(data => {
        setTimeout(function () {
          dispatch(loadPublicChannelsSuccess(data));
        }, 150);
      });
  };
};

Редуктор:

case types.UNREAD_MESSAGE_SUCCESS:
        const um = Object.assign(state.unreadMessages, {[action.info]: action.unreadMessages});
    return {
      ...state,
      unreadMessages: um
    };

Контейнер - внутри я подключаю состояние картыдля пропов с непрочитанными сообщениями и передачи моему компоненту в виде проппов:

const mapStateToProps = state => {
return {
  publicChannels: state.chat.publicChannels,
  unreadMessages: state.chat.unreadMessages,
};
}

Компонент:

render() {
    // rendering all public channels
    const renderPublicChannels = ({ item, unreadMessages }) => {
      return (
        <ListItem
          title={item.info.Name}
          titleStyle={styles.title}
          rightTitle={(this.props.unreadMessages || {} )[item.id] > 0 && `${(this.props.unreadMessages || {} )[item.id]}`}
          rightTitleStyle={styles.rightTitle}
          rightSubtitleStyle={styles.rightSubtitle}
          rightSubtitle={(this.props.unreadMessages || {} )[item.id] > 0 && "unread"}
          chevron={true}
          bottomDivider={true}
          id={item.Name}
          containerStyle={styles.listItemStyle}
        />
      );
    };


    return (
        <View style={styles.channelList}>
          <FlatList
            data={this.props.publicChannels}
            renderItem={renderPublicChannels}
            keyExtractor={(item, index) => index.toString()}
            extraData={[this.props.publicChannels, this.props.unreadMessages]}
            removeClippedSubviews={false}
          />
        </View>
    );
  }
}

Ответы [ 2 ]

1 голос
/ 25 октября 2019

Object.assign объединит все в первый объект, представленный в качестве аргумента, и возвратит тот же объект. В редуксе вам нужно создать новую ссылку на объект, иначе изменение не гарантируется. Используйте это

const um = Object.assign({}, state.unreadMessages, {[action.info]: action.unreadMessages});
// or
const um = {...state.unreadMessages, [action.info]: action.unreadMessages }
0 голосов
/ 25 октября 2019

Object.assign () не возвращает новый объект. Из-за чего в редукторе unreadMessages указывает на один и тот же объект, а компонент не перерисовывается.

Используйте это в своем редукторе

const um = Object.assign({}, state.unreadMessages, {[action.info]: action.unreadMessages});
...