a state mutation was detected inside a dispatch (NOT “in between” dispatch)

左心房为你撑大大i 提交于 2019-12-11 16:24:34

问题


...inside a dispatch, in the path: "chat.messages.0' Take a look at the reducer(s) handling the action {'type': 'chat', 'payload': {'sender': 'you', 'body': 'foo'}}`

My reducer:

chatMessage.js:
export default (state, action) => {
    return Object.assign({}, {
        ...state,
        messages: [...state.messages, action.payload]
    })
}

Interestingly, if I use messages=[] in my Chat component, I don't get this error.

export default class Chat extends React.Component {
  state = {...this.props.data, input: "", toggle: false}

  _renderItem = ({item}) => {
    return <ChatMessageRow data={item} />
  }

  render() {
    // var {messages} = this.state
    var messages = []
return (
      <View style={styles.container}>
        <FlatList
          inverted
          renderItem={this._renderItem}
          style={styles.logWrapper}
          data={messages.reverse()}
          extraData={this.state.toggle}
        />

from my main view, which is bound to Redux:

return (...other views... check if tabIndex == 1, show <Chat data={this.props.chat} ... />

I ran into an issue earlier with the FlatList rendering in Chat not updating and I had to do a

this.setState({messages: messages.push(newMessage), toggle: !this.state.toggle})

to update the state so the Flat List would recognize it's changed.

Now I am loading my data from a Chat store using connect and redux, then passing that data into the component.

I get the error when I try to reload the Chat component after adding chat messages. Weirdly I can get one to update but after adding one it will not show others.

At first I think this is a problem in my reducer so I rewrite the reducer to use the Object assign and array spread operator.

Now I think it is related to the rendering which is unexpected.

How do I debug this?

EDIT:

It's not "it works with adding 1 message". It's - I can bring the view out of focus and back into focus one time. So..

Open Chat Tab Observer 1 message Add N messages to store using redux actions Change tabs, revert back to Chat Observer N messages added Add M messages Change tabs, click back to Chat tab Error shows

EDIT:

I tried

using ...spread, but redux still throws warning about state mutation 's suggestion doing

    export default (state, action) => {
        return Object.assign({}, {
            ...state,
            messages: state.messages.map(value => Object.assign({}, value)).concat(action.payload)
        })
    }

in my reducer, same error.

EDIT:

My reducer is update to chatMessage.js

I think the issue is in how I'm calling this.

I am writing a websocket controller. I don't need to wait for a response when I send a message like I would with an HTTP response.

My websocket controller:

    onMessage = ({data}) => {
        const json = JSON.parse(data)
        if (json) {
            if (json.status) {
                const reducer = this.stateFilters[json.status]
                if (reducer) {
                    reducer(json.body)
                } else {
                    console.log("No reducer")
                }
            }
        }
    }

the websocket controller is created in my View component:

my main view

import {ChatStateFilters} from '../../reducers/chat'

const mapDispatch = { chatMessage }

this.wsController = new WebSocketController({
      stateFilters: {chatMessage: this.props.chatMessage},

from the chat reducer file (that contains the chatMessage reducer)

Those state filters get created when I create my slice.

The value of stateFilter['chatMessage'] -- which is the value of what gets bound to my View's prop in mapDispatchToProp

is this function:

let fn = (payload) => {
      return dispatch => {
          dispatch(stateFilters[actionName](payload))
      }
    }
exportedStateFilters[actionName] = fn

I think the problem is somewhere in here^... somehow the dispatch is firing, updating state but redux doesn't know the dispatch is finished

EDIT 2:

I thought the lack of async may have been an issue. So I changed the stateFilter (the fn that gets bound to my prop in the view) to this:

   let fn = (payload) => {
      return dispatch => {
        post("", {}, true)
        .then(response => {
          dispatch(stateFilters[actionName](payload))
        })
        .catch(error => {
          dispatch(stateFilters[actionName](payload))
        })
      }
    }

and now it works a few more times.. then gives me the error "A state mutation was detected between dispatches".

My chat message reducer is still

export default (state, action) => {
    let messages2 = Object.assign([], [...state.messages, action.payload])
  return Object.assign({}, {...state, messages: messages2 })
}

so why is this error happening?

来源:https://stackoverflow.com/questions/58120646/a-state-mutation-was-detected-inside-a-dispatch-not-in-between-dispatch

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!