Type and payload are being dispatched without calling it - react-native

I'm currently working on a react-native app with a chat feature. I'm using redux to store my states. So after pressing the send-button to send a message, an action is called to send the message to firebase and show it on the screen afterwards.
My current problem is that while the action I called dispatches the right type/payload, another type/payload is also being dispatched, which is not being dispatched in the called action. Apparently somehow another action is being called containing the type/payload.
The code of the action which is not being called is the following:
const getChatData = (chatIDs, userName, uid) => async dispatch => {
console.log('hasdhkhwerljlkbgkanndhadndngknnjnjsnfjskdnfjsuvhshdifhuishiduhfuishdkfnkjsndf')
const chatData = []
for (const key of chatIDs) {
[...]
// get message
firebase.database().ref('messages/' + key)
.orderByChild('timestamp').limitToLast(1)
.on('child_added', snapshot => {
const { text, timestamp, user } = snapshot.val();
const { name } = user;
chatData.push({ key, members: displayNameArray, text, timestamp, name })
dispatch({
type: GET_CHAT_DATA,
payload: chatData
})
})
})
}
}
As I said, the type GET_CHAT_DATA is being dispatched eventhough this action is not being called. Furthermore, the console.log doesn't show the long test message, which should mean that this action is not being called, right?
What could cause this weird behaviour?
Thank you so much!

So the thing is even though you did not execute the function but in there you registered an event on firebase
.on('child_added', snapshot => { })
Now whenever this child_added event will trigger, the handler will be executed.
That is why your dispatcher is running because its inside the event handler.
firebase.database().ref('messages/' + key)
.orderByChild('timestamp').limitToLast(1)
.on('child_added', snapshot => {
// this is the event handler which is executing
// when the "child_added" event is triggered
const { text, timestamp, user } = snapshot.val();
const { name } = user;
chatData.push({ key, members: displayNameArray, text, timestamp, name })
dispatch({
type: GET_CHAT_DATA,
payload: chatData
})
})
})

Related

Quick-blox react native QB.chat.EVENT_TYPE.USER_IS_TYPING handler not working for me

please help for using this typing handler.this is handling for react native typing handler for but not getting any message during user typing please help.here using quick typing handler to catch the user typing but not working properly...please help,My code is here...
const emitter = new NativeEventEmitter(QB.chat);
function userTypingHandler(event) {
const {
type, // name of the event (the one you've subscribed for)
payload, // event data
} = event;
const {
dialogId, // in dialog with id specified
userId, // user with id specified is typing
} = payload;
// handle as
console.log("user is typing", userId);
}
emitter.addListener(QB.chat.EVENT_TYPE.USER_IS_TYPING, userTypingHandler);
return () =>{
emitter.removeListeners(
QB.chat.EVENT_TYPE.USER_IS_TYPING, userTypingHandler
);
}
}, [QB.chat.EVENT_TYPE.USER_IS_TYPING]);

Can I return value from action creator using redux-thunk?

I've seen a lot of examples of async action creators, but they all do some sort of fetching and pushing data to redux store and return nothing. I need another logic that looks something like:
const createUserAction = (user) => {
firestore().collection('users').add(user)
.then(result => {
dispatch({type: 'SET_USER', payload: {...user, id: result.id}})
})
}
I need to return result.id from createUserAction to navigate to page that displays user by his id. In my imagine it should work like
createUserAction({name: John}).then(id => navigation.navigate('UserDetailPage', {userId: id}))
I don't know how to implement that and I'll be glad if somebody can help
Returning values from action creators is a No-Go. The solution for this scenario that I've used and think is better is to do the redirect in the async action itself:
// afterCreation = callback function with one argument, the created user
const createUserAction = async (user, afterCreation) => {
const createdUser = await firestore().collection('users').add(user);
dispatch({type: 'SET_USER', payload: {...user, id: createdUser.id}});
afterCreation(createdUser);
};
createUserAction(
{name: John},
// Pass callback to action creator
(user) => navigation.navigate('UserDetailPage', {userId: user.id})
);

vuex 3.6 why is my state object undefined when using it inside a method

I am building an application using vue 2.6.11 and vuex 3.6.0
The page I am building is for an event registration. The ActiveEvent is fetched from the database (Event ID, Date, Location etc) using an API
The registration form first asks for an email address. On blur of the email field we then fire the checkEmail(). This should do one or two API calls. The first call checks to see if we have the email address in the database and returns the ParticipantID, and if we do then a second call is made to see if the participant is already registered against this event using Event.EventID and ActiveUser.ParticipantID
The stucture of the page being loaded is a page component <EventDetail> called from the router. This has a main component <EventRegistration> which calls two separate sub-components: <EventRegistrationBlurb> which gets the state.ActiveEvent passed as a prop and <EventRegistrationForm> which is fetching the state.ActiveEvent directly. The outer component <EventRegistration> is responsible for fetching the Event data from the API and setting state.ActiveEvent which is does successfully,
What I am failing to understand is why when I call checkEmail in my component, this.ActiveEvent is undefined. The puter component is fetching the API and setting the state correctly as the blurb component is correctly rendering it. If I put the ActiveEvent object into the template for the EventRegistrationForm it renders correctly, it is just not being set in time for the binding to be made to the method checkEmail()
I have the following code in my sub-component <EventRegistrationForm>: (NOTE, ActiveEvent is set by an outer component and does get set correctly)
methods: {
...mapActions(['CheckParticipantByEmail']),
async checkEmail () {
const payload = {
email: this.form.email,
EventID: this.ActiveEvent.EventID // <-- THIS IS UNDEFINED???
}
await this.CheckParticipantByEmail(payload)
}
},
computed: {
...mapState(['ActiveEvent', 'ActiveUser'])
}
and then in my store:
state: {
ActiveEvent: {},
ActiveUser: {}
},
mutations: {
SET_ACTIVE_EVENT (state, payload) {
state.ActiveEvent = payload
},
CHECK_PARTICIPANT_BY_EMAIL (state, payload) {
state.ActiveUser = payload
},
GET_PARTICIPANT_FOR_EVENT (state, payload) {
state.ActiveUser = payload
}
},
actions: {
async CheckParticipantByEmail ({ commit }, payload) {
console.log('payload', payload)
const baseUrl = process.env.VUE_APP_API_URL
const url = `${baseUrl}getParticipantbyEmail`
const { email, EventID } = payload
const response = await axios.post(
url,
{
EmailAddress: email
}
)
const User = await response.data[0]
commit('CHECK_PARTICIPANT_BY_EMAIL', User)
if (User.ParticipantID > 0) {
const baseUrl = process.env.VUE_APP_API_URL
const url2 = `${baseUrl}getParticipantForEvent`
const payload2 = {
ParticipantID: User.ParticipantID,
EventID: EventID
}
alert('URL2: ' + url2)
alert('payload2 participant: ' + payload2.ParticipantID)
alert('payload2 event: ' + payload2.EventID)
const response2 = await axios.post(
url2,
payload2
)
// console.log('response: ', response.data[0])
const payload3 = response2.data[0]
commit('GET_PARTICIPANT_FOR_EVENT', payload3)
}
}
}
As usual, it turns out to be an interface error between the chair and the keyboard. This page is normally accessed from a list of events which is an array of objects where the identifier is EventID. When calling the separate events the identifier is just ID so the code in the payload2 should read
const payload2 = {
ParticipantID: User.ParticipantID,
EventID: ID // <- NOTE change of identifier.
}
I think I will update the API to return a consistent identifier and avoid the headache later on. Only wasted about 3 hours on this...

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

...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?

The user object is empty in app even though it is returned from backend server

Here is an _onPress in my react native app. The purpose of this function is to retrieve the user object and pass it to the next component after the user clicks an item. async/await is used for the db retrieval in _getUser. I can see the user object on the server but myself receives nothing and is empty. I am not sure why the myself is empty. Should _getUser be called in the constructor instead?
async _onPress(id) {
let myself = await _getUser();
if (!myself) console.log("_getUser return nothing in Chat!");
this.props.navigation.navigate("Chat", {eventId: id, user: myself});
}
As _getUser() is returning promise and probably _onPress is getting called directly from ToucableOpacity or some touch responder button, you can resolve promise and then take necessary action like:
_onPress(id) {
_getUser()
.then((data) => {
if (!data) {
console.log("_getUser return nothing in Chat!");
return
}
this.props.navigation.navigate("Chat", { eventId: id, user: data });
})
.catch(err => { console.log(err) })
}