首页 > 解决方案 > redux-saga: Actions must be plain objects

问题描述

I have a problem with my saga and I don't have any idea what is wrong. Im getting an error like Actions must be plain objects. Use custom middleware for async actions while using react redux. Here is my code.

container/index.js

class AppContainer extends Component {

    componentDidMount() {
        const { actions: { onFetchPhoto } } = this.props;
        onFetchPhoto();
    }

    render() {
        return (
            <App />
        );
    }
}


const mapDispatchToProps = (dispatch) => ({
    actions: {
        onFetchPhoto: () => dispatch(fetchPhoto())
    }
})


export default connect(null, mapDispatchToProps)(AppContainer);

actions/index.js

export const FETCH_PHOTO_REQUEST = "FETCH_PHOTO_REQUEST";
export const FETCH_PHOTO_SUCCESS = "FETCH_PHOTO_SUCCESS";
export const FETCH_PHOTO_FAILURE = "FETCH_PHOTO_FAILURE";

export function fetchPhoto(payload) {
    return {
        type: FETCH_PHOTO_REQUEST
    }
}
export function fetchPhotoSuccess(payload) {
    return {
        type: FETCH_PHOTO_SUCCESS,
        payload
    }
}
export function fetchPhotoFailure(error) {
    return {
        type: FETCH_PHOTO_SUCCESS,
        payload: {
            error
        }
    }
}

sagas/index.js

function* fetchRandomPhoto() {
    //yield put(fetchPhoto());

    const {
        response,
        error
    } = yield call(fetchRandomPhotoApi)

    if (response) {
        yield put(fetchPhotoSuccess(response))
    } else {
        yield put(fetchPhotoFailure(error))
    }
}

function* watchLoadRandomPhoto() {
    try {
        while (true) {
            yield takeLatest(FETCH_PHOTO_REQUEST, fetchRandomPhoto);
        }
    }
    catch(error) {
        console.error("error in saga", error)
    }
}

export default function* rootSaga() {
    yield fork(watchLoadRandomPhoto)
}

services/index.js

import axios from 'axios';
import {
    URL,
    PUBLIC_KEY
} from 'src/constants/config';

import {
    schema,
    normalize
} from 'normalizr'

export function fetchRandomPhotoApi() {
    return axios({
            url: `${URL}/photos/random`,
            timeout: 10000,
            method: 'get',
            headers: {
                'Autorization': `Client-ID ${PUBLIC_KEY}`
            },
            responseType: 'json'
        })
        .then((response) => {
            const { data } = response.data;
            console.log("d");
            if (data) {
                return ({
                    response: {
                        id: data.id,
                        url: data.urls.full,
                        title: data.location.title
                    }
                })
            }
        })
       .catch(error => error)
}

store/configureStore.js

import rootReducer from 'src/reducers/root';
import rootSaga from 'src/sagas';


export default function configureStore() {
    const logger = createLogger();
    const sagaMiddleware = createSagaMiddleware();
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

    const store = createStore(
        rootReducer,
        compose(
            applyMiddleware(
                sagaMiddleware,
                logger,
                composeEnhancers
            ),
        )
    );

    sagaMiddleware.run(rootSaga);

    return store;
}

I waste 2 day to fix this problem, but no result. Chrome showed me this error:

enter image description here

标签: reactjsreact-reduxredux-saga

解决方案


The source of your problem lies within fetchRandomPhotoApi function. Without knowing what that looks like I can't say for certain but if it is for example a function that return a promise you should be calling like

const { response, error } = yield call(fetchRandomPhotoApi)

Notice the lack of brackets in the call.

Update

From your edit I can now see that the promise is not resolved in your api call. You want that function to return an object instead of the actual promise to pass on to your actions. Something on the lines of:

axios({...etc}).then(response => response).catch(error => error)

推荐阅读