Я пытаюсь React SSR, используя Redux и Redux-saga.
Я могу заставить клиентский рендеринг работать, но хранилище сервера, похоже, никогда не получает данные и не ждет данных перед рендерингом сервера HTML.
. js
import express from 'express';
import renderer from "./helpers/renderer";
import createStore from "./helpers/createStore";
import {matchRoutes} from 'react-router-config';
import Routes from "./client/Routes";
import rootSaga from "./client/saga";
const app = express();
app.use(express.static('public'));
app.get('*', (req, res) => {
const store = createStore();
const branch = matchRoutes(Routes, req.path);
const promises = branch.map(({ route }) => {
return route.loadData ? route.loadData(store) : Promise.resolve(null);
});
store.runSaga(rootSaga).done.then(() => {
res.send(renderer(req, store)) // helper method to load static router and provider
}) // Not required after Update 2 , Promise.All should work ..
});
app.listen(3000, () => {
console.log('Listening on Port 3000');
})
небольшая сага
import { put, takeEvery, all, call } from 'redux-saga/effects'
import {FETCH_USERS, SAVE_USERS} from "../actions";
import axios from 'axios';
export function* fetchUsers() {
const res = yield call(getUsers);
yield put({ type: SAVE_USERS, payload: res.data});
}
const getUsers = () => {
const response = axios.get('http://react-ssr-api.herokuapp.com/users');
return response;
}
export function* actionWatcher() {
yield takeEvery(FETCH_USERS, fetchUsers)
}
export default function* rootSaga() {
yield all([
actionWatcher()
])
}
ошибка
TypeError: Cannot прочитать свойство 'then' из undefined в /Users/rahsinwb/Documents/Mine/code/SSR/build/bundle.js:309:39
Что мне здесь не хватает? Или есть какой-нибудь проверенный способ прослушивания концовки саги? Я думал, что мой помощник loadData в компоненте с store.dispatch
для первоначального вызова действия вернет обещание, но это никогда не работает.
LoadData
const loadData = (store) => {
store.dispatch({type: FETCH_USERS});
}
Обновление
Добавлено это в мой индекс. js Файл
store.runSaga(rootSaga).toPromise().then(() => {
branch.map(({ route }) => {
return route.loadData ? route.loadData(store) : Promise.resolve(null);
});
res.send(renderer(req, store))
})
Теперь код компилируется без ошибок, но проблема в том, что сага отправляет действие из метода loadData, то есть FetchData. До того, как fetchData вызовет действие Save_DATA в саге, упомянутой выше, мой вызов отменяется, как я полагаю, и редуктор остается пустым, из-за чего html не загружается с данными.
Как мы знаете, что загрузка данных для функции генератора завершена, начиная с действия, инициированного до действия по загрузке данных? на редуктор, как только сообщение, что я должен сделать компонент на сервере
Update2
Также проверил lib , но для по какой-то странной причине он вызывает проблемы с регенератором, но я не думаю, что библиотека нужна для такой цели, так как я планирую повторно использовать ту же сагу для клиентских вызовов Redux и хочу сохранить изменения отдельно. index. js
console.log(promises); // no promise returned undefined
//setTimeout((function() {res.send(renderer(req, store))}), 2000);
Promise.all(promises).then(
res.send(renderer(req, store))
)
Добавление Set Timeout помогает, и я могу получить данные на сервере, а затем выполнить рендеринг, так что теперь проблема заключается в том, что нам нужно как-то дождаться Генератор, чтобы решить, затем вызвать render.
Обновление 3
Добавил способ обойти эту проблему в качестве ответа, но я не чувствую, что это лучше решить и можно абстрагировать эту логику c out