admin管理员组文章数量:1277901
I'm making a React/Redux app. In one of my actions, dispatch
is firing 6-8 times when called for no apparent reason. See addMarkersRequestAddress
below in the action file for my ponent:
export function addMarkersSuccess(response) {
return {
type: 'addMarkersSuccess',
status: 'success',
response: response,
receivedAt: Date.now(),
};
}
export function addMarkersFailure(error) {
return {
type: 'addMarkersFailure',
status: 'error',
error: error,
receivedAt: Date.now(),
};
}
export function addMarkersRequestCoordinates(submitFormData) {
// Why is this always returning addMarkersFailure? Is it possibly related to why it always fires multiple times?
// Same code as in virtualFenceWalk actions
return (dispatch) => {
console.log('running addMarkersRequestCoordinates');
console.log('submitFormData: ',submitFormData);
let JSONbody = JSON.stringify(submitFormData);
console.log('JSONbody: ',JSONbody);
fetch('http://localhost:8080/virtualFence', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSONbody
}).then(function(response){
dispatch(addMarkersSuccess(response));
}).catch(function(error) {
dispatch(addMarkersFailure(error));
});
}
}
export function addMarkersRequestAddress(submitFormData) {
return (dispatch) => {
console.log('running addMarkersRequestAddress');
console.log('submitFormData: ',submitFormData);
let JSONbody = JSON.stringify(submitFormData);
console.log('JSONbody: ',JSONbody);
// Make a request to a backend route that gets the coordinates from the Google Maps API
fetch('http://localhost:8080/virtualFenceAddress', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSONbody
}).then(function(response){
console.log('addMarkersRequestAddress success');
console.log('response: ',response);
dispatch(addMarkersSuccess(response));
}).catch(function(error) {
console.log('addMarkersRequestAddress failure');
console.log('error: ',error);
dispatch(addMarkersFailure(error));
});
}
}
When this code runs, addMarkersSuccess
will fire 6-8 times. It is somehow related to dispatch
specifically, because if I remove the dispatch
calls and leave only the console logs, addMarkersSuccess
fires once as expected and that's it. It also seems unrelated to fetch
or asynchronicity since an identical oute occurs if fetch
is removed and the same thing is tried in the main body of the function.
Here is the container wrapping around the ponent (since I've narrowed it down to an issue with how dispatch
is called, as without dispatch
other parts of the action only fire once, maybe there is an issue with how dispatch
is set up here?):
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, View, Text, TouchableOpacity, TouchableHighlight } from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import VirtualFence from '../ponents/VirtualFence';
import * as VirtualFenceActions from '../actions/virtualFence';
const styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'flex-end',
alignItems: 'center',
},
back: {
margin: 10,
fontSize: 20,
},
});
// Map the Redux state to props
@connect(
state => ({
bigState: state,
markers: state.markers,
}),
dispatch => bindActionCreators(VirtualFenceActions, dispatch),
)
export default class VirtualFenceContainer extends Component {
render() {
return (
<View style={styles.container}>
<VirtualFence {...this.props} />
</View>
);
}
}
Here is where the action is called in the ponent itself:
render() {
const {
addMarkersRequestAddress, addMarkersSuccess, addMarkersFailure
} = this.props;
return (
<View>
<TouchableOpacity onPress={this.toggleModal}>
<Text style={styles.bottomText}>Add markers by street address</Text>
</TouchableOpacity>
<Modal isVisible={this.state.isVisible}>
<View style={{ flex: 1 }}>
<TouchableOpacity onPress={this.toggleModal}>
<Text style={styles.bottomText}>Hide me!</Text>
</TouchableOpacity>
<Form
ref="form"
type={Points}
options={pointsOptions}
/>
<Button title="Add form field" onPress={this.addFormField}></Button>
<Button title="Delete form field" onPress={this.deleteFormField}></Button>
<Button
title="Submit markers"
onPress={(argument)=>addMarkersRequestAddress(this.refs.form.getValue())}
/>
</View>
</Modal>
</View>
);
}
While not answering my question, some other answers here and elsewhere seemed to hint that the resolution may have something to do with my configureStore.js
file, so here it is:
/* eslint global-require: 0 */
import { Platform } from 'react-native';
import { createStore, applyMiddleware, pose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers';
// Presumably I need to add the other action files here somehow? Nothing seems to change as long as one file is listed...
import * as actionCreators from './actions/activityTracker';
let poseEnhancers = pose;
if (__DEV__) {
// Use it if Remote debugging with RNDebugger, otherwise use remote-redux-devtools
/* eslint-disable no-underscore-dangle */
poseEnhancers = (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ||
require('remote-redux-devtools')poseWithDevTools)({
name: Platform.OS,
...require('../package.json').remotedev,
actionCreators,
});
/* eslint-enable no-underscore-dangle */
}
const enhancer = poseEnhancers(applyMiddleware(thunk));
// I think the problem with multiple dispatches may be in here
// See
export default function configureStore(initialState) {
const store = createStore(reducer, initialState, enhancer);
if (module.hot) {
module.hot.accept(() => {
store.replaceReducer(require('./reducers').default);
});
}
return store;
}
Please note that I don't really know what this file is doing. I began the app using react-native-boilerplate so this file is taken from there. If changes need to be made there, it would be super appreciated if you can detail what exactly those changes do.
EDIT 1: When this post was originally written, all dispatches after the first threw errors. After some further work in other parts of the application, the additional firings all log successful now. However, the essential question (the cause of the multiple firings) remains.
EDIT 2: Added the container wrapping around the ponent.
I'm making a React/Redux app. In one of my actions, dispatch
is firing 6-8 times when called for no apparent reason. See addMarkersRequestAddress
below in the action file for my ponent:
export function addMarkersSuccess(response) {
return {
type: 'addMarkersSuccess',
status: 'success',
response: response,
receivedAt: Date.now(),
};
}
export function addMarkersFailure(error) {
return {
type: 'addMarkersFailure',
status: 'error',
error: error,
receivedAt: Date.now(),
};
}
export function addMarkersRequestCoordinates(submitFormData) {
// Why is this always returning addMarkersFailure? Is it possibly related to why it always fires multiple times?
// Same code as in virtualFenceWalk actions
return (dispatch) => {
console.log('running addMarkersRequestCoordinates');
console.log('submitFormData: ',submitFormData);
let JSONbody = JSON.stringify(submitFormData);
console.log('JSONbody: ',JSONbody);
fetch('http://localhost:8080/virtualFence', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSONbody
}).then(function(response){
dispatch(addMarkersSuccess(response));
}).catch(function(error) {
dispatch(addMarkersFailure(error));
});
}
}
export function addMarkersRequestAddress(submitFormData) {
return (dispatch) => {
console.log('running addMarkersRequestAddress');
console.log('submitFormData: ',submitFormData);
let JSONbody = JSON.stringify(submitFormData);
console.log('JSONbody: ',JSONbody);
// Make a request to a backend route that gets the coordinates from the Google Maps API
fetch('http://localhost:8080/virtualFenceAddress', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSONbody
}).then(function(response){
console.log('addMarkersRequestAddress success');
console.log('response: ',response);
dispatch(addMarkersSuccess(response));
}).catch(function(error) {
console.log('addMarkersRequestAddress failure');
console.log('error: ',error);
dispatch(addMarkersFailure(error));
});
}
}
When this code runs, addMarkersSuccess
will fire 6-8 times. It is somehow related to dispatch
specifically, because if I remove the dispatch
calls and leave only the console logs, addMarkersSuccess
fires once as expected and that's it. It also seems unrelated to fetch
or asynchronicity since an identical oute occurs if fetch
is removed and the same thing is tried in the main body of the function.
Here is the container wrapping around the ponent (since I've narrowed it down to an issue with how dispatch
is called, as without dispatch
other parts of the action only fire once, maybe there is an issue with how dispatch
is set up here?):
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, View, Text, TouchableOpacity, TouchableHighlight } from 'react-native';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import VirtualFence from '../ponents/VirtualFence';
import * as VirtualFenceActions from '../actions/virtualFence';
const styles = StyleSheet.create({
container: {
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
justifyContent: 'flex-end',
alignItems: 'center',
},
back: {
margin: 10,
fontSize: 20,
},
});
// Map the Redux state to props
@connect(
state => ({
bigState: state,
markers: state.markers,
}),
dispatch => bindActionCreators(VirtualFenceActions, dispatch),
)
export default class VirtualFenceContainer extends Component {
render() {
return (
<View style={styles.container}>
<VirtualFence {...this.props} />
</View>
);
}
}
Here is where the action is called in the ponent itself:
render() {
const {
addMarkersRequestAddress, addMarkersSuccess, addMarkersFailure
} = this.props;
return (
<View>
<TouchableOpacity onPress={this.toggleModal}>
<Text style={styles.bottomText}>Add markers by street address</Text>
</TouchableOpacity>
<Modal isVisible={this.state.isVisible}>
<View style={{ flex: 1 }}>
<TouchableOpacity onPress={this.toggleModal}>
<Text style={styles.bottomText}>Hide me!</Text>
</TouchableOpacity>
<Form
ref="form"
type={Points}
options={pointsOptions}
/>
<Button title="Add form field" onPress={this.addFormField}></Button>
<Button title="Delete form field" onPress={this.deleteFormField}></Button>
<Button
title="Submit markers"
onPress={(argument)=>addMarkersRequestAddress(this.refs.form.getValue())}
/>
</View>
</Modal>
</View>
);
}
While not answering my question, some other answers here and elsewhere seemed to hint that the resolution may have something to do with my configureStore.js
file, so here it is:
/* eslint global-require: 0 */
import { Platform } from 'react-native';
import { createStore, applyMiddleware, pose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers';
// Presumably I need to add the other action files here somehow? Nothing seems to change as long as one file is listed...
import * as actionCreators from './actions/activityTracker';
let poseEnhancers = pose;
if (__DEV__) {
// Use it if Remote debugging with RNDebugger, otherwise use remote-redux-devtools
/* eslint-disable no-underscore-dangle */
poseEnhancers = (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ||
require('remote-redux-devtools').poseWithDevTools)({
name: Platform.OS,
...require('../package.json').remotedev,
actionCreators,
});
/* eslint-enable no-underscore-dangle */
}
const enhancer = poseEnhancers(applyMiddleware(thunk));
// I think the problem with multiple dispatches may be in here
// See https://stackoverflow./questions/49734848/redux-dispatch-fires-multiple-times
export default function configureStore(initialState) {
const store = createStore(reducer, initialState, enhancer);
if (module.hot) {
module.hot.accept(() => {
store.replaceReducer(require('./reducers').default);
});
}
return store;
}
Please note that I don't really know what this file is doing. I began the app using react-native-boilerplate so this file is taken from there. If changes need to be made there, it would be super appreciated if you can detail what exactly those changes do.
EDIT 1: When this post was originally written, all dispatches after the first threw errors. After some further work in other parts of the application, the additional firings all log successful now. However, the essential question (the cause of the multiple firings) remains.
EDIT 2: Added the container wrapping around the ponent.
Share Improve this question edited Jul 27, 2018 at 13:10 223seneca asked Jul 23, 2018 at 13:23 223seneca223seneca 1,1764 gold badges22 silver badges49 bronze badges 6- Can you show how you use these actions in your ponent? Please show a minimal reproducible example. Note the word "plete". – Code-Apprentice Commented Jul 23, 2018 at 14:22
- I've added the render function from the ponent where this action is called. – 223seneca Commented Jul 23, 2018 at 14:24
- Please read the link I gave in my previous ment. – Code-Apprentice Commented Jul 23, 2018 at 14:25
- Where are you executing the addMarkersRequestCoordinates function? Your reducer action seems ok. – Marco Mendão Commented Jul 23, 2018 at 14:25
- I did read the link. What is the issue? – 223seneca Commented Jul 23, 2018 at 14:26
4 Answers
Reset to default 3The cause of my problem turned out to be in the file where I call the bineReducers helper function. I did not suspect this file had anything to do with the problem, so I had not posted it. For ponents with multiple keys in the initial state object, I incorrectly thought I had to do an import for each key, when in fact I needed a single import for each reducer file. I imported six variables from the virtualFence
reducer, and each one caused dispatch
to fire.
This is the incorrect version:
import { bineReducers } from 'redux';
import nav from './nav';
import virtualFence from './virtualFence';
import latitude from './virtualFence';
import longitude from './virtualFence';
import latitudeDelta from './virtualFence';
import longitudeDelta from './virtualFence';
import markers from './virtualFence';
export default bineReducers({
nav,
latitude,
longitude,
latitudeDelta,
longitudeDelta,
markers,
virtualFence,
});
And this is the correct version:
import { bineReducers } from 'redux';
import nav from './nav';
import virtualFence from './virtualFence';
export default bineReducers({
nav,
virtualFence,
});
are you using preventDefault() when calling event this might be the case:
function ActionLink() {
function handleClick(e) {
e.preventDefault();
console.log('The link was clicked.');
}
return (
<a href="#" onClick={handleClick}>
Click me
</a>
);
}
use preventdefault to disallow to call method when page is loading
<Button title="Add form field" onPress={this.addFormField}></Button>
<Button title="Delete form field" onPress={this.deleteFormField}></Button>
<Button
title="Submit markers"
onPress={(argument)=>addMarkersRequestAddress(this.refs.form.getValue())}
/>
So you state:
addMarkersSuccess
will fire once, followed by several firings ofaddMarkersFailure
addMarkersFailure
only gets called when there is an error. This error, of course, contains all the information you need to solve the problem. In particular, it has a stack that indicates not only the exact place the error was fired, but a plete call stack that indicates the entire call chain leading up to the error.
When a Promise
has several stages, each stage has an opportunity to fail. A catch following any of the stages will be passed the error.
So:
Promise.resolve('This is just a string, and no error')
.then(theString => {
throw new Error('This is not the original promise result, but a new one: A rejection.');
})
.catch(err => {
console.log('Something went wrong. Maybe it happened in the original promise.');
console.log('Maybe it happened later. To find out, look closely at this:');
console.log(err.stack);
});
In your case, it's probably dispatch
that throws. Now, there's nothing wrong with dispatch
itself, but when it goes to call your reducer, the reducer is probably doing something wrong and throwing an error. This in turn leads your .catch
callback (aka the rejection handler) to be called.
Since you did not include your reducer code I can't point out the error in it. However, you should be able to find it by examining the error message and stack.
In your addMarkersRequestAddress
action, try to return the dispatch
in .then()
like:
.then((response) => {
dispatch(addMarkersSuccess(response));
}).catch((error) => {
dispatch(addMarkersFailure(error));
});
Maybe this will work.
本文标签: javascriptReactNativeRedux dispatch firing multiple times in actionStack Overflow
版权声明:本文标题:javascript - React-NativeRedux dispatch firing multiple times in action - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741256522a2366778.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论