принудительно перерисовать компонент после изменения состояния редукса - PullRequest
0 голосов
/ 25 февраля 2020

У меня есть стековый навигатор с двумя экранами: «Сообщения» и «Сообщение». На экране «Сообщения» я хочу получить обзор всех людей, с которыми я общаюсь, + последнее сообщение в беседе. Я храню все разговоры в редуксе, а не на сервере. Мое состояние избыточности выглядит следующим образом:

const state = {
    user = [
        {
            userId: 1,
            username: John,
            messages: [...array of messages send to John or from John...]
        },
        {
            userId: 2,
            username: Jane,
            messages: [...array of messages send to Jane or from Jane...]
        }
        ...
    ]
}

На экране «Сообщения» у меня есть компонент FlatList, который перебирает массив пользователей в состоянии избыточности:

const users = useSelector(state => state.messages.users)

const renderUserItem = user => {
    return (
        <View>
            <Text>{user.username}</Text>
            <Text>{user.messages[user.messages.length-1].message</Text>
        </View>
    )
}

<FlatList
    data={messages}
    renderItem={({item, index}) => renderUserItem(item)} />

Это работает, я получаю обзор разговоров, которые у меня есть + последнее сообщение. Когда я нажимаю на беседу на экране «Сообщения», я отправляюсь на экран «Сообщения», где у меня есть другой FlatList со всеми сообщениями этой конкретной беседы. Этот код не имеет значения, но работает на.

Проблема заключается в том, что при добавлении нового сообщения (через экран «Сообщение») обновляется состояние избыточности: (dispatch(addMessage(userId, message)), но при переходе Возвращаясь к экрану «Сообщения», я не вижу последнее сообщение, экран не перерисовывается, даже если изменилось состояние избыточности. Когда я делаю жесткий refre sh, он работает.

Как заставить экран перерисоваться, когда изменилось состояние избыточности. Я использую компоненты без состояния .

Редактировать: Мой редуктор:

const initialState = {
    users: []
}

const MessagesReducer = (state = initialState, action) => {
    let array, index, user, messages
    switch (action.type) {
        case 'START_CONVERSATION':
            // action.user is an object which contains userId and username
            array = state.users
            index = array.findIndex(e => e.userId === action.user.userId)
            if (index > -1) {
                // conversation already exists
            } else {
            object = {
                userId: action.user.userId,
                username: action.user.username,
                messages: []
            }
            array.push(object)
            return {
                users: array
            }
        break
        case 'ADD_MESSAGE':
             // action.userId contains the userId of the conversation partner
             // action.message is an object with direction, 
             // message and timestamp in it
             array = state.users
             index = array.findIndex(e => e.userId === action.userId)
             user = array[index]
             user.messages.push({
                 direction: action.message.direction,
                 message: action.message.message,
                 timestamp: action.message.timestamp
             }
             // get the old user object out of the array
             array.splice(index, 1)
             // push the new user object to the beginning of the array
             array.unshift(user)  
             return {
                user: array
             }
        break
        default:
            return state
        break
    }
}

1 Ответ

3 голосов
/ 25 февраля 2020

Вы изменяете состояние, из-за которого оно выглядит так, как будто состояние вообще не изменилось. Это означает отсутствие повторного рендеринга.

Измените это array = state.users на array = [...state.users].

Это создаст новую ссылку на массив вместо изменения предыдущего состояния, что вызовет повторный рендеринг как и ожидалось.


При втором взгляде я заметил еще несколько проблем. Это не остановит повторный рендеринг, но все еще изменяет предыдущее состояние, поэтому его следует исправить.

Измените это:

user = array[index] // user is still a reference to previous state
user.messages.push({ // messages is still a reference to previous state
  ...

на следующее:

// Create a new user object based on the previous values
// Then add to the messages array by creating a new array with your new entry
user = {
  ...array[index], 
  messages: [
    ...array[index].messages, 
    {
      direction: action.message.direction,
      message: action.message.message,
      timestamp: action.message.timestamp
    }
  ]
}

// OR
user = {...array[index], messages: [...array[index].messages]}
user.messages.push({...})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...