代码之家  ›  专栏  ›  技术社区  ›  223seneca

响应本地/还原调度在操作中多次触发

  •  11
  • 223seneca  · 技术社区  · 6 年前

    我正在制作一个React/Redux应用程序。在我的一次行动中, dispatch 在没有明显原因的情况下被要求射击6-8次。见 addMarkersRequestAddress 以下是我的组件的操作文件:

    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));
            });
    
      }
    
    }
    

    当此代码运行时, addMarkersSuccess 将发射6-8次。它在某种程度上与 派遣 具体来说,因为如果我移除 派遣 只留下控制台日志, 添加标记成功 按预期发射一次,就这样。它似乎也与 fetch 或异步性,因为如果 取来 在函数的主体中尝试相同的操作。

    这是包装组件的容器(因为我已经将其缩小到 派遣 被称为 派遣 动作的其他部分只发射一次,也许有一个问题是如何 派遣 是否在这里设置?):

    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 '../components/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>
        );
      }
    }
    

    下面是在组件本身中调用操作的位置:

    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>
        );
      }
    

    虽然没有回答我的问题,但这里和其他地方的一些其他答案似乎暗示这项决议可能与我的 configureStore.js 文件,这里是:

    /* eslint global-require: 0 */
    
    import { Platform } from 'react-native';
    import { createStore, applyMiddleware, compose } 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 composeEnhancers = compose;
    if (__DEV__) {
      // Use it if Remote debugging with RNDebugger, otherwise use remote-redux-devtools
      /* eslint-disable no-underscore-dangle */
      composeEnhancers = (window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ||
        require('remote-redux-devtools').composeWithDevTools)({
        name: Platform.OS,
        ...require('../package.json').remotedev,
        actionCreators,
      });
      /* eslint-enable no-underscore-dangle */
    }
    
    const enhancer = composeEnhancers(applyMiddleware(thunk));
    
    // I think the problem with multiple dispatches may be in here
    // See https://stackoverflow.com/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;
    }
    

    请注意,我真的不知道这个文件在做什么。我开始使用 react-native-boilerplate 所以这个文件是从那里取的。如果需要在那里进行更改,如果您能详细说明这些更改的具体作用,我们将不胜感激。

    编辑1:当最初写这篇文章时,所有发帖后的第一个抛出错误。在应用程序的其他部分做了一些进一步的工作之后,附加的触发现在都成功了。然而,关键问题(多次点火的原因)仍然存在。

    编辑2:添加了环绕组件的容器。

    4 回复  |  直到 6 年前
        1
  •  1
  •   223seneca    6 年前

    我的问题的原因是在我称之为 combineReducers 帮助程序函数。我没有怀疑这个文件与问题有任何关系,所以我没有发布它。对于初始状态对象中具有多个键的组件,我错误地认为必须为每个键执行导入,而实际上我需要为每个reducer文件执行单个导入。我从 virtualFence 减速器,每一个都造成 dispatch 开火。

    这是不正确的版本:

    import { combineReducers }       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 combineReducers({
      nav,
      latitude,
      longitude,
      latitudeDelta,
      longitudeDelta,
      markers,
      virtualFence,
    });
    

    这是正确的版本:

    import { combineReducers }           from 'redux';
    import nav                           from './nav';
    import virtualFence                  from './virtualFence';
    
    export default combineReducers({
      nav,
      virtualFence,
    });
    
        2
  •  0
  •   Navin Gelot    6 年前

    调用事件时是否使用PreventDefault(),可能是这样的:

    function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }
    
      return (
        <a href="#" onClick={handleClick}>
          Click me
        </a>
      );
    }
    

    使用PreventDefault不允许在加载页时调用方法

    <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())}
                />
    
        3
  •  0
  •   DDS    6 年前

    所以你说:

    addMarkersSuccess 将发射一次,随后几次发射 addMarkersFailure

    addmarkers失败 只有在出现错误时才会被调用。当然,这个错误包含了解决问题所需的所有信息。特别是,它有一个堆栈,不仅指示错误被激发的确切位置,还指示错误前的整个调用链的完整调用堆栈。

    当A Promise 有几个阶段,每个阶段都有失败的机会。任何阶段后面的catch都将传递错误。

    所以:

    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);
      });
    

    在你的情况下,可能是 dispatch 那就扔。现在,没什么问题 派遣 本身,但当它调用 你的 减速器,减速器可能做错了什么,抛出了一个错误。这反过来又导致你 .catch 要调用的回调(也称为拒绝处理程序)。

    因为您没有包含您的reducer代码,所以我不能指出其中的错误。但是,您应该能够通过检查错误消息和堆栈来找到它。

        4
  •  -1
  •   dazs    6 年前

    在你的 addMarkersRequestAddress 动作,尝试返回 dispatch 在里面 .then() 像:

    .then((response) => {
          dispatch(addMarkersSuccess(response));
        }).catch((error) => {
          dispatch(addMarkersFailure(error));
        });
    

    也许这会奏效。