如何使用 Redux-Saga 和 Hooks 调用 API

Posted

技术标签:

【中文标题】如何使用 Redux-Saga 和 Hooks 调用 API【英文标题】:How to use Redux-Saga with Hooks to call API 【发布时间】:2020-05-26 05:17:39 【问题描述】:

我正在尝试使用 Redux-saga 中间件来避免异步函数错误,我正在使用 React Hooks,我连接了 Redux-Saga 并执行了 function* yield 函数,但我不知道为什么它没有读取我的操作拦截它,它给了我同样的错误:

错误:动作必须是普通对象。使用自定义中间件进行异步操作。

代码: Store.js

import createSagaMiddleware from 'redux-saga';
import rootReducer from './RootReducer'
import watchFetchImages from '../middleware/saga';

const sagaMiddleware = createSagaMiddleware();
const store = createStore(
    rootReducer,
    applyMiddleware(sagaMiddleware)
  );
  sagaMiddleware.run(watchFetchImages);

export default store;

Actions.js

import axios from 'axios';
import  GetCategories  from './actionTypes'
import GetImages from './actionTypes'

export function fetchCategories() 
    var url = 'http://localhost:4000/all_categories';
    return (dispatch) => 
        return axios.get(url).then((res) => 
            dispatch(
                type: GetCategories,
                payload: res.data
            )
        )
     



export function fetchImages()
    var url ='/all_categories';
    return(dispatch) => 
        return axios.get(url).then((res)=>
            dispatch(
                type:GetImages,
                payload:res.data
            )  

        )
    


Reducers.js

import  GetCategories , GetImages  from "../redux/actions/actionTypes"
const initialState = 
    categories: [],
    images:[]
;

const rootReducer = (state = initialState, action) => 
    switch (action.type) 
        case GetCategories:
            return ...state, categories: state.categories.concat(action.payload)
        case GetImages:
            return...state,images:action.payload
        default:
        return state;

    
;
export default rootReducer;

Saga.js

import takeEvery,delay from 'redux-saga/effects'



function* getImagesAsync()
    yield delay(4000);
    console.log('api called')



export function* watchFetchImages()

    yield takeEvery("GetImages",getImagesAsync);



Home.js 我在哪里调用 redux 操作

const  HomePage = props => 



    useEffect(()=>props.getImages())
    console.log(props)

 const mapStateToProps = (images) => (
        images
    )
    const mapDispatchToProps= dispatch =>(

        getImages: () => dispatch(fetchImages())
    )

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

索引.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import  Provider  from "react-redux";
import store from '../src/redux/store';
import * as serviceWorker from './serviceWorker';

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


任何人都可以帮助我吗??

【问题讨论】:

在将store 传递给它时如何使用&lt;Provider&gt;?你能分享index.js吗?谢谢! @norbitrial 我确实添加了 index.js ,如果您除了我遇到的问题之外还有任何其他 cmets,请通知我,我对 redux 和 hooks 还是新手 Saga.js 中,您是在导出watchFetchImages 函数还是只是从示例中丢失? @norbitrial 例子中是导出的,是不是也需要导出其他函数getImagesAsync? 错误说的是真的。我使用 Redux Thrunk 在操作中创建函数。 npmjs.com/package/redux-thunk 【参考方案1】:

几周前我刚刚参与了一个使用 redux-saga 处理 websockets 的项目,我遇到了一个几乎类似的问题。 SageMiddleware 确实适用于 saga 函数,但要将函数用于我使用 redux-thrunk 的操作。小例子:

import  
	createStore, 
	applyMiddleware, 
	compose 
 from "redux";

import createSagaMiddleware from 'redux-saga'; 
import thunk from "redux-thunk"; 

import reducer from '../reducers';

const storeEnhancers =  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const store = createStore(
	reducer,
	(localStorage['storage']) ? JSON.parse(localStorage['storage']) : ,
	storeEnhancers(applyMiddleware(sagaMiddleware, thunk))
);

我希望这对您有所帮助。

【讨论】:

谢谢,但我只需要使用 Sagas【参考方案2】:

所以我没有看到store 设置有任何问题,applyMiddleware 位于正确的位置。我看到的问题是您可以调用dispatch 的生成器函数,但是这里有几个缺点可以进一步阅读:Dispatching actions to the store。

相反,您可以调用 put 来调度操作。通过创建效果中间件会处理这些,并将适当的操作发送到商店。因此,作为documentation 的更好解决方案,它指出:

相反,我们需要相同的声明式解决方案。创建一个普通的 javascript 对象来指示中间件我们需要调度一些动作,并让中间件执行真正的调度。这样我们就可以用同样的方式测试 Generator 的 dispatch:检查产生的 Effect 并确保它包含正确的指令。

为此,该库提供了另一个函数 put 来创建调度效果。

Saga.js 中尝试以下更改:

function* getImagesAsync() 
    // here you can call your API
    const payloadImages = // result from API response

    yield put(type: 'GetImages', payloadImages);


export default function* watchFetchImages() 
    yield takeEvery('GetImages', getImagesAsync);

希望对你有帮助!

【讨论】:

我试图这样做还是一样的错误,我试图在reducer中添加另一个动作案例来处理saga中间件仍然相同的错误,我认为错误来自takeEvery函数无法识别动作'GetImages'所以它没有拦截它,仍然不知道如何修复它我的新代码:Saga.js function* getImagesAsync() const payloadImages = axios.get('/all_images');; yield put(type: 'GetImagesSaga', payload:payloadImages); export function* watchFetchImages() yield takeEvery("GetImages",getImagesAsync);

以上是关于如何使用 Redux-Saga 和 Hooks 调用 API的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 redux-saga 处理异步 API 调用?

如何使用 redux-saga 在 API 响应中检查过期的 JWT 令牌?

无法弄清楚如何使用 redux-saga-test-plan 测试 redux-saga 功能

redux-saga:如何以编程方式为产量创建多个调用/副作用?

如何将 redux-saga 添加到我的 Web 扩展中?

如何防止 redux-saga 调用我的 api 调用两次?