gpt4 book ai didi

reactjs - 如何使用 redux-saga 在 getInitialProps 中获取数据。然后在 getInitialProps 方法中从 redux store 获取响应?

转载 作者:行者123 更新时间:2023-12-04 12:37:05 29 4
gpt4 key购买 nike

我完成了使用 create-react-app (CSR) 创建的 React 应用程序的编码,但我现在正在使用 Next.js 框架重写整个应用程序以获得更好的 SEO 性能。

在重写它时,我很难弄清楚如何正确处理 redux 和 redux-saga 来执行获取和存储数据的过程。
在这个项目中使用 Next.js 的主要原因是利用 getInitialProps 方法,在第一次页面加载发生之前在服务器端获取数据。但出于某种原因,我无法“等待” Redux 调度完成并按时获取获取的数据。

所以最终发生的事情是我分派(dispatch)了获取数据的操作,但是在初始服务器端页面加载期间它没有按时存储在 redux 存储中。但是当我使用 next/link 更改路由时,数据进来了,但只在客户端,在服务器端渲染发生之后。

所以它有点违背了使用 Next.js 的目的。

这段新代码与 create-react-app 项目非常相似,只是做了一些小改动以适应 Next.js 项目的要求。

这是我的代码。

./pages/_app.js

import App from 'next/app';
import { Provider } from 'react-redux';
import withRedux from 'next-redux-wrapper';
import withReduxSaga from 'next-redux-saga';
import makeStore from '../store/index';

class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
const pageProps = Component.getInitialProps
? await Component.getInitialProps(ctx)
: {};
return { pageProps };
}

render() {
const { Component, pageProps, store } = this.props;
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
);
}
}

export default withRedux(makeStore)(MyApp);

./pages/index.jsx:

import React from 'react';
import { useRouter } from 'next/router';

import Layout from '../components/Layout';
import SubNavBarCategories from '../components/Pages/Home/SubNavBarCategory';

import * as BlogActions from '../store/actions/blog/categories';


const Blog = (props) => {
const router = useRouter();
const {
blogCategories,
} = props;


return (
<Layout>
<SubNavBarCategories blogCategories={blogCategories} />
</Layout>
);
};


Blog.getInitialProps = async ({ isServer, store }) => {
await store.execSagaTasks(isServer, (dispatch) => {
dispatch(BlogActions.getRecentCategories(5));
});

console.log('await store:', await store.getState().blog.blogCategories);
//output: await store: { data: [], loading: true, fetched: false, error: false }
//expected something like this:
// await store: { data: ['test1', 'category', 'crypto', 'test4', 'Day trade'] loading: false, fetched: true, error: false }

return {
blogCategories: await store.getState().blog.blogCategories,
};
};

export default Blog;

./store/index.js
import {
createStore,
applyMiddleware,
compose,
} from 'redux';
import createSagaMiddleware, { END } from 'redux-saga';

import rootReducer from './reducers';
import rootSaga from './sagas';

const sagaMiddleware = createSagaMiddleware();
const makeStore = (initialState) => {
const composeEnhancers = (typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose;

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

store.runSaga = () => {
if (store.saga) {
return;
}
store.sagaTask = sagaMiddleware.run(rootSaga);
};


store.stopSaga = async () => {
if (!store.saga) {
return;
}
store.dispatch(END);
await store.saga.done;
store.saga = null;
};

store.execSagaTasks = async (isServer, tasks) => {
store.runSaga();
tasks(store.dispatch);

await store.stopSaga();

if (!isServer) {
store.runSaga();
}
};

store.runSaga();
return store;
};

export default makeStore;

./store/actions/blog/blog.js
export function getRecentCategories(number) {
return {
type: 'REQUEST_RECENT_CATEGORIES',
payload: {
number,
},
};
}

./store/reducers/blog/blog.js
import update from 'immutability-helper';

const initialState = {
blogCategories: {
data: [],
loading: false,
fetched: false,
error: false,
},
};

export default function blog(state = initialState, action) {
switch (action.type) {
case 'REQUEST_RECENT_CATEGORIES':
return update(state, {
blogCategories: {
loading: { $set: true },
},
});
case 'SUCCESS_RECENT_CATEGORIES':
console.log('actions:', action.payload.data);
//output: actions: blogCategories [ 'test1', 'category', 'crypto', 'test4', 'Day trade' ]
return update(state, {
blogCategories: {
data: { $set: action.payload.data },
loading: { $set: false },
fetched: { $set: true },
error: { $set: false },
},
});
case 'FAILURE_RECENT_CATEGORIES':
return update(state, {
blogCategories: {
fetched: { $set: true },
error: { $set: true },
},
});
default:
return state;
}
}

./store/sagas/blog/getRecentCategories.js
import {
put,
call,
} from 'redux-saga/effects';

import 'isomorphic-fetch';

async function getRecentCategoriesApi(number) {
const res = await fetch(`http://localhost:5000/blog/get/categories/newest/${number}`, {
method: 'GET',
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json',
},
});
const data = await res.json();
return data;
}

export default function* asyncGetRecentCategoriesApi(action) {
try {
const response = yield call(getRecentCategoriesApi, action.payload.number);

yield put({ type: 'SUCCESS_RECENT_CATEGORIES', payload: { data: response } });
} catch (err) {
yield put({ type: 'FAILURE_RECENT_CATEGORIES' });
}
}

正如你所看到的,这个应用程序是一个非常普通的 react redux-saga 应用程序。除了使用 redux-saga 从后端获取数据之外,其他一切都在正常工作。

有没有办法让 getInitialProps 方法按预期与 redux 和 redux-saga 一起工作?

最佳答案

使用 redux-saga 示例查看官方 Next.js 示例。

https://github.com/zeit/next.js/tree/canary/examples/with-redux-saga

关于reactjs - 如何使用 redux-saga 在 getInitialProps 中获取数据。然后在 getInitialProps 方法中从 redux store 获取响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60310565/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com