如何解决错误:“操作必须是普通对象”?

时间:2019-07-26 07:15:19

标签: reactjs asynchronous redux action redux-saga

我对使用Sagas并不陌生,我无法解决“操作必须是普通对象。使用自定义中间件进行异步操作”的问题。

我附上了所有必要的代码。已经伤了脑筋,解决了这个问题。 希望对您有所帮助。

我查看了sagas的文档,但未发现有关此错误的任何信息。 我还看了反应样板,那里已经有渣气,但是我想在CRA上做

动作

import { AXIOS } from "../api";

import { takeLatest, put, call } from "redux-saga/effects";

export const GET_GENRES_PENDING = "GENRES::GET_GENRES_PENDING";
export const GET_GENRES_FULFILLED = "GENRES::GET_GENRES_FULFILLED";
export const GET_GENRES_REJECTED = "GENRES::GET_GENRES_REJECTED";

export const getGenresPending = () => ({
  type: GET_GENRES_PENDING
});

export const getGenresFulfilled = data => ({
  type: GET_GENRES_FULFILLED,
  payload: data
});

export const getGenresRejected = error => ({
  type: GET_GENRES_REJECTED,
  payload: error
});

export function* getGenresAction() {
  try {
    yield put(getGenresPending());
    const data = yield call(() => {
      return AXIOS.get(
        "/movie/list?api_key=5fcdb863130c33d2cb8f1612b76cbd30&language=ru-RU"
      ).then(response => {
        console.log(response);
      });
    });
    yield put(getGenresFulfilled(data));
  } catch (error) {
    yield put(getGenresRejected(error));
  }
}

export default function* watchFetchGenres() {
  yield takeLatest("FETCHED_GENRES", getGenresAction);
}

商店

import { applyMiddleware, compose, createStore } from "redux";
import createSagaMiddleware from "redux-saga";
import rootReducer from "./reducers";
import watchFetchGenres from "./actions/getGenresAction";

const sagaMiddleware = createSagaMiddleware();

export function configureStore(initialState) {
  const middleware = [sagaMiddleware];
  const composeEnhancers =
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
  const store = createStore(
    rootReducer,
    initialState,
    composeEnhancers(applyMiddleware(...middleware))
  );
  sagaMiddleware.run(watchFetchGenres);
  return store;
}

index.js

import React from "react";
import ReactDOM from "react-dom";

import { Provider } from "react-redux";

import App from "./containers/App";

import * as serviceWorker from "./serviceWorker";

import { configureStore } from "./core/configureStore.js";

const store = configureStore({});

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

serviceWorker.unregister();

App.js

import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";

import MoviesContainer from "./MoviesContainer/MoviesContainer";
import FilterContainer from "./FilterContainer/FilterContainer";

import { Container, GlobalStyle } from "./style.js";

export default function App() {
  return (
    <Container className="app">
      <GlobalStyle />
      <Router>
        <Route exact path="/" component={FilterContainer} />
        <Route path="/movies" component={MoviesContainer} />
      </Router>
    </Container>
  );
}

容器

import React, { useState, useEffect } from "react";

import { connect } from "react-redux";
import { bindActionCreators } from "redux";

import watchFetchGenres from "../../core/actions/getGenresAction";

import Card from "../../components/Card/Card";
import Button from "../../components/Button/Button";
import TextInput from "../../components/TextInput/TextInput";
import { TitleH1, TitleH2, TitleCard } from "../../components/Title/Title";

import { Container, SecondaryContainer } from "../style.js";

class FilterContainer extends React.Component {
  // const dispatch = useDispatch();

  // useEffect(() => {
  //   getGenresAction();
  //   // fetch('https://api.themoviedb.org/3/genre/movie/list?api_key=5fcdb863130c33d2cb8f1612b76cbd30&language=en-US')
  // });

  componentDidMount() {
    this.props.watchFetchGenres();
  }
  render() {
    return (
      <Container>
        <TitleH1 title="Фильтры" />
        <SecondaryContainer>
          <TextInput placeholder="Введите название фильма" />
        </SecondaryContainer>
        <SecondaryContainer filters>
          <Card>
            <TitleCard title="Фильтр по жанру" />
          </Card>
          <Card>
            <TitleCard title="Фильтр по рейтингу" />
          </Card>
          <Card>
            <TitleCard title="Фильтр по году" />
          </Card>
        </SecondaryContainer>
        <SecondaryContainer>
          <Button primary value="Применить фильтры" placeholder="lala" />
        </SecondaryContainer>
      </Container>
    );
  }
}

const mapStateToProps = state => ({
  genres: state.genres
});

const mapDispatchToProps = dispatch =>
  bindActionCreators({ watchFetchGenres }, dispatch);

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(FilterContainer);

1 个答案:

答案 0 :(得分:0)

  

bindActionCreators({watchFetchGenres},dispatch);

watchFetchGenres不是动作创建者,因此这是不正确的。动作创建者是返回动作的函数。您的代码中有3个示例:

export const getGenresPending = () => ({
  type: GET_GENRES_PENDING
});

export const getGenresFulfilled = data => ({
  type: GET_GENRES_FULFILLED,
  payload: data
});

export const getGenresRejected = error => ({
  type: GET_GENRES_REJECTED,
  payload: error
});

这些是您应该绑定的事物类型。

您的传奇正在监听“ FETCHED_GENRES”类型的动作,因此现有的3个动作创建者将无法使用该动作。您可能需要创建另一个动作创建者,如:

export const fetchGenres = () => ({
  type: 'FETCHED_GENRES',
});

然后在mapDispatchToProps中,您将使用此动作创建者:

const mapDispatchToProps = dispatch =>
  bindActionCreators({ fetchGenres }, dispatch);

并更新其调用位置:

componentDidMount() {
  this.props.fetchGenres();
}