реакции должны быть обычными объектами - PullRequest
0 голосов
/ 13 сентября 2018

У меня проблема " Действия должны быть простыми объектами. Используйте пользовательское промежуточное ПО для асинхронных действий. "

Я использую реагирование с этим образцом (https://github.com/react-boilerplate/react-boilerplate/) Я трачу 1 день, чтобы решить эту проблему, но безрезультатно. Я пытался переместить запрос на выборку к действию (без саги) и результат тот же.

Мой компонент:

...
import { compose } from 'redux';
import injectReducer from 'utils/injectReducer';
import injectSaga from 'utils/injectSaga';
import { successFetching } from './actions';
import reducer from './reducers';
import saga from './saga';

class NewsListPage extends React.PureComponent {

  componentDidMount() {
    const { dispatch } = this.props
    dispatch(saga())
  }

  ...
};

NewsListPage.propTypes = {
  isFetching: PropTypes.bool.isRequired,
  isSuccess: PropTypes.bool.isRequired,
  items: PropTypes.array.isRequired,
  dispatch: PropTypes.func.isRequired,
}

const selector = (state) => state;

const mapStateToProps = createSelector(
  selector,
  (isFetching, isSuccess, items) => ({ isFetching, isSuccess,items })
);

function mapDispatchToProps(dispatch) {
  return {
    dispatch,
  };
}
const withReducer = injectReducer({ key: 'NewsList', reducer });
const withSaga = injectSaga({ key: 'NewsList', saga });
const withConnect = connect(mapStateToProps, mapDispatchToProps);

export default compose(
    withReducer,
    withSaga,
    withConnect
  )(NewsListPage);

Мои действия:

export const NEWS_FETCH_LOADING = 'NEWS_FETCH_LOADING';
export const NEWS_FETCH_FAILURE = 'NEWS_FETCH_FAILURE';
export const NEWS_FETCH_SUCCESS = 'NEWS_FETCH_SUCCESS';

export function preFetching() {
  return {
    type: NEWS_FETCH_LOADING,
  }
}

export function successFetching(json) {
  return {
    type: NEWS_FETCH_SUCCESS,
    payload: json
  }
}

export function failureFetching(error) {
  return {
    type: NEWS_FETCH_FAILURE,
    payload: error
  }
}

Мои редукторы:

...
import { NEWS_FETCH_LOADING, NEWS_FETCH_FAILURE, NEWS_FETCH_SUCCESS } from './actions'

const INITIAL_STATE = {
  isFetching: false,
  isSuccess: false,
  items: []
};

function NewsListReducer(state = INITIAL_STATE, action) {
  switch (action.type) {
    case NEWS_FETCH_LOADING:
    case NEWS_FETCH_FAILURE:
      return Object.assign({}, state, {
        isFetching: true,
        isSuccess: false
      })
    case NEWS_FETCH_SUCCESS:
      return Object.assign({}, state, {
        isFetching: false,
        isSuccess: true,
        items: action.payload,
      })
    default:
      return Object.assign({}, state)
  }
}

export const rootReducer = combineReducers({
  NewsListReducer
})
export default rootReducer

Моя сага:

import { call, put, select, takeLatest } from 'redux-saga/effects';
import {NEWS_FETCH_LOADING, NEWS_FETCH_FAILURE, NEWS_FETCH_SUCCESS, preFetching, successFetching, failureFetching} from './actions';
import request from 'utils/request';

export function* getNews() {
  const requestURL ='%MY_URL%';

  try {
    const req = yield call(request, requestURL);
    yield put(successFetching(req));
  } catch (err) {
    yield put(failureFetching(err));
  }
}

export default function* NewsListSaga() {
  yield takeLatest(NEWS_FETCH_SUCCESS, getNews);
}

EDIT: @ Аллео Индонг, я попробовал твой совет, и это почти сработало.

Я изменяю в компоненте mapDispatchToProps значение

export function mapDispatchToProps(dispatch) {
  return {
    getData: () => dispatch(loadNews()),
  };
}

И добавить новую функцию в actions.js

export function loadNews() {
  return {
    type: NEWS_FETCH_SUCCESS,
  }
}

Но теперь ajax отправляется каждые секунды , как во время цикла. Я попытался позвонить this.props.getData(); в componentDidMount и constructor и результат такой же.

РЕДАКТИРОВАТЬ 2 В компонент добавляю

import * as  actionCreators from './actions';
import { bindActionCreators } from 'redux';

В конструкторе я изменяю

constructor(props) {
  super(props);

  const {dispatch} = this.props;

  this.boundActionCreators = bindActionCreators(actionCreators, dispatch)
}

Но здесь dispatch не определено и в componentDidMount тоже. И изменить mapDispatchToProps на

export function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators(actionCreators, dispatch),
  };
}

1 Ответ

0 голосов
/ 13 сентября 2018

Здравствуйте @AND и добро пожаловать в stackoverflow! Как я упоминал в комментарии к основному сообщению, вы отправляете ГЕНЕРАТОР вместо объекта на вашем

dispatch(saga());

Вот пример, чтобы помочь вам

В свой компонент импортируйте действия, которые вы хотите использовать следующим образом.

import * actionCreators from './actions';
import { bindActionCreators } from 'redux';

Узнайте больше о bindActionCreators здесь введите описание ссылки здесь

Это импортирует все экспортированные создатели actionCreator, которые вы там создали. По моему мнению, вам больше не нужны successFetching и failureFetching, так как вы можете отправить эти действия позже в своей саге

Тогда в вашем mapDispatchToProps вы захотите зарегистрировать этого actioncreator

function mapDispatchToProps(dispatch) {
    return {
        ...bindActionCreators(actionCreators, dispatch),
    };
}

Тогда в вашей саге, я также хочу указать на некоторые проблемы. Сначала твоя функция

export default function* NewsListSaga() {
    yield takeLatest(NEWS_FETCH_SUCCESS, getNews);
}

На самом деле это то, что мы называем watcher, где он наблюдает, когда было отправлено определенное действие, в этой функции вы уже ждете NEWS_FETCH_SUCCESS до вызова getNews, что неправильно, потому что вы сначала должны выполнить FETCHING прежде чем вы узнаете, если это не удалось или успех, так что да, эта функция должна быть такой

export default function* NewsListSaga() {
    yield takeLatest(NEWS_FETCH_LOADING, getNews);
}

Это просто означает, что вы будете take all the latest NEWS_FETCH_LOADING actions that was dispatched and will call the getNews`.

затем в функции генератора getNews вы можете сделать это следующим образом

export function* getNews() {
    const requestURL ='%MY_URL%';

    try {
        const req = yield call(request, requestURL);
        yield put({type: NEWS_FETCH_SUCCESS, req});
    } catch (err) {
        yield put({type: NEWS_FETCH_FAILED, err});
    }
}

здесь

const req = yield call(request, requestURL);

Вы говорите, что будете ждать результата запроса / услуги, который вы позвонили, это может быть обещание.

Тогда вот почему вам больше не нужны функции successFetching и failureFetching, поскольку вы можете сделать это следующим образом. yield put({type: NEWS_FETCH_SUCCESS, req});

Последний важный шаг, который вы должны сделать сейчас, - вызвать actionCreator внутри вашего componentDidMount()

вот так

componentDidMount() {
    const { preFetching } = this.props;
    preFetching();
}
...