Reit Redux操作在初始化之前被调用

问题描述 投票:0回答:1

我对Redux和整个Redux-Saga还是很陌生,想使用React-Boilerplate尝试一个小项目,该项目基本上只是进行API调用并遍历数据。我目前遇到一个问题,我已经坚持了几个小时。也许你有个主意?

我的React组件看起来像这样:

import React, { useEffect } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { compose } from 'redux';

import { useInjectSaga } from 'utils/injectSaga';
import { useInjectReducer } from 'utils/injectReducer';
import { 
  makeSelectDevices, 
  makeSelectLoading, 
  makeSelectError 
} from './selectors';
import reducer from './reducer';
import { fetchDevices } from './actions';
import saga from './saga';

export function LeafletMap(props) {
  const {devices, loading, error, fetchDevices } = props;

  useInjectReducer({ key: 'leafletMap', reducer });
  useInjectSaga({ key: 'leafletMap', saga });

  useEffect(() => {
    fetchDevices();
  }, [fetchDevices]);

  if (loading) return(<div>Loading...</div>)
  return (
    <div>
      { !error ? 
        <Map center={[47.3, 9.9]} zoom={9} style={{height: '500px'}}>
          <TileLayer 
              url='https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' 
              attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
          />
            { devices && devices.map((device)=> {
                let coordinates = [device.latitude, device.longitude];
                return (
                  <Marker key={device.id} position={coordinates}></Marker>
                ); 
            })}
        </Map>
        : ''
      }
    </div>
  );
};

LeafletMap.propTypes = {
  devices: PropTypes.array,
  loading: PropTypes.bool,
  error: PropTypes.any,
};

const mapStateToProps = createStructuredSelector({
  devices: makeSelectDevices(),
  loading: makeSelectLoading(),
  error: makeSelectError(),
});

function mapDispatchToProps(dispatch) {
  return {
    fetchDevices: () => dispatch(fetchDevices())
  };
}

const withConnect = connect(
  mapStateToProps,
  mapDispatchToProps,
);

export default compose(withConnect)(LeafletMap);

[当我安装组件时,我使用useEffect钩子调度使用mapDispatchToProps绑定到道具的动作。动作文件如下所示:

import { 
  FETCH_DATA, 
  FETCH_DATA_ERROR, 
  FETCH_DATA_SUCCESS,
  CLICK_DEVICE
} from './constants';

export function fetchDevices() {
  return {
    type: FETCH_DATA,
  };
}

export function fetchDevicesSuccess(devices) {
  return {
    type: FETCH_DATA_SUCCESS,
    devices
  };
}

export function fetchDevicesError(error) {
  return {
    type: FETCH_DATA_ERROR,
    error
  };
}

我的传奇然后对FETCH_DATA动作做出了反应,并调用了一个生成器来从我的本地API中获取数据:

import { all, call, put, takeEvery } from 'redux-saga/effects';
import request from 'utils/request';
import { fetchDevicesSuccess, fetchDevicesError } from './actions';
import { FETCH_DATA } from './constants';

function* fetchDevicesAsync() {
  yield takeEvery(FETCH_DATA, fetchAllDevices);
}

function* fetchAllDevices() {
  try {
    const requestUrl = '/api/devices';
    const devices = yield call(request, requestUrl);

    yield put(fetchDevicesSuccess(devices));
  } catch (error) {
    yield put(fetchDevicesError(error.toString()));    
  }
}

export default function* rootSaga() {
  yield all([fetchDevicesAsync()]);
}

这将触发我的减速器,如下所示:

import produce from 'immer';
import { 
  FETCH_DATA, 
  FETCH_DATA_ERROR, 
  FETCH_DATA_SUCCESS,
} from './constants';
export const initialState = {
  devices: [],
  loading: true,
  error: false,
};

/* eslint-disable default-case, no-param-reassign */
const leafletMapReducer = (state = initialState, action) =>
  produce(state, () => {
    switch (action.type) {
      case FETCH_DATA:
        state.loading = true;
        state.error = false;
        break;
      case FETCH_DATA_ERROR:
        state.loading = false
        state.error = action.error;
        break;
      case FETCH_DATA_SUCCESS:
        state.loading = false;
        state.error = false;
        state.devices = action.devices;
        break;
    }
  });

export default leafletMapReducer;

我的问题是,一切似乎都正常,但是我的动作既没有显示在Redux DevTools中,也没有在初始渲染后更新我的组件。似乎该动作是在@@ INIT事件之前分派的。

action is missing but data is in the store

知道为什么会这样吗?

谢谢!

编辑:

以防它与我的选择器有关:

import { createSelector } from 'reselect';
import { initialState } from './reducer';

/**
 * Direct selector to the leafletMap state domain
 */

const selectLeafletMapDomain = state => state.leafletMap || initialState;

/**
 * Other specific selectors
 */

const makeSelectDevices = () =>
  createSelector(
    selectLeafletMapDomain,
    leafletMapState => leafletMapState.devices
  ); 

const makeSelectLoading = () =>
  createSelector(
    selectLeafletMapDomain,
    leafletMapState => leafletMapState.loading,
  );

const makeSelectError = () =>
  createSelector(
    selectLeafletMapDomain,
    leafletMapState => leafletMapState.error,
  );

/**
 * Default selector used by LeafletMap
 */

const makeSelectLeafletMap = () =>
  createSelector(selectLeafletMapDomain, leafletMapState => leafletMapState.toJS());

export default makeSelectLeafletMap;
export { 
  selectLeafletMapDomain, 
  makeSelectDevices, 
  makeSelectLoading, 
  makeSelectError
};
reactjs redux react-redux redux-saga react-boilerplate
1个回答
0
投票

亲自发现问题:)问题出在我的减速器中:

const leafletMapReducer = (state = initialState, action) =>
  produce(state, () => {             // <-- here
    switch (action.type) {
      case FETCH_DATA:
        state.loading = true;
        state.error = false;
        break;

我在这里错误地改变了状态,导致错误。正确的解决方案是:

const leafletMapReducer = (state = initialState, action) =>
  produce(state, draftState => {     // use draftState instead of normal state
    switch (action.type) {
      case FETCH_DATA:
        draftState.loading = true;   //<------
        draftState.error = false;    //<------
        break;
© www.soinside.com 2019 - 2024. All rights reserved.