React + Redux + SSR: невозможно найти хранилище только при переходе непосредственно к подключенному компоненту - PullRequest
0 голосов
/ 18 февраля 2019

Я относительно новичок в SSR с React и Redux, поэтому я предполагаю, что совершаю простую ошибку, которая отражает мое непонимание базовых структур.Тем не менее, я собираюсь положить голову через стену, так что здесь.Надеюсь, что кто-то может помочь.

Если я пытаюсь перейти непосредственно к корневой странице (/), я получаю ошибку Could not find "store" in the context of "Connect(Home)".В моем случае App содержит мою общую логику навигации и глобальный контент, а (/) отображает компонент Home.Если я перехожу на страницу, которая НЕ подключается к Redux (например, Условия предоставления услуг), и ТО затем перехожу на мою домашнюю страницу, она отображается идеально.Я предполагаю, что это какая-то проблема маршрутизации на стороне сервера, но я прочитал все, что могу найти в Интернете, попробовал все возможные варианты обработки состояния / хранилища / контекста и не могу ее решить.

Вот скелет моего кода.

renderer.js

[...]

const modules = [];
const routerContext = {};

const bundle = (
    <Loadable.Capture report={m => modules.push(m)}>
        <ReduxProvider store={store}>
            <StaticRouter location={req.baseUrl} context={routerContext}>
                <CookiesProvider cookies={req.universalCookies}>
                    <App />
                </CookiesProvider>
            </StaticRouter>
        </ReduxProvider>
    </Loadable.Capture>
    );

const html = ReactDOMServer.renderToString(bundle);

if (routerContext.url) {
  redirect(301, routerContext.url);
}

// inject into HTML

[...]

configureStore.js

[...]

const createStoreWithMiddleware = compose(applyMiddleware(ReduxThunk))(createStore);

export default function configureStore(initialState = {}) {
    return createStoreWithMiddleware(rootReducer, initialState);
};

index.js (клиент)


const store = configureStore( window.__REDUX_STATE__ || {} );

const AppBundle = (
    <ReduxProvider store={store}>
        <BrowserRouter>
            <CookiesProvider>
                <App />
            </CookiesProvider>
        </BrowserRouter>
    </ReduxProvider>
);

window.onload = () => {
    Loadable.preloadReady().then(() => {
        ReactDOM.hydrate(
            AppBundle,
            document.getElementById('root')
        );
    });
};

app.js ("/" отображает компонент Home)

[...]

export default withCookies(App);

[...]

home.js

[...]

export default connect(mapStateToProps)(Home);

[...]

Ответы [ 3 ]

0 голосов
/ 21 февраля 2019

На стороне сервера также необходимо создать свой магазин, состояние которого берется в качестве исходного состояния для рендеринга на стороне клиента.На стороне клиента я вижу, что вы сделали это:

const store = configureStore( window.__REDUX_STATE__ || {} )  

Аналогичные действия необходимо выполнить и на стороне сервера.

На стороне сервера необходимо выполнить следующие действия:store = createStore(rootReducer), чтобы создать магазин, который используется здесь <ReduxProvider store={store}> в rendered.js.

Пожалуйста, возвращайтесь для любых сомнений или разъяснений.

0 голосов
/ 15 марта 2019

Я наконец-то определил проблему.Я использовал сервер Express для размещения страниц, отображаемых на сервере, одновременно с Node-клиентом.К сожалению, сервер создавал один экземпляр React, а клиент создавал другой экземпляр React.В результате, несмотря на то, что код выглядел правильно, мое хранилище Redux не передавалось по иерархии компонентов для того же контекста React.

У меня ушло навсегда отладка и идентификация. Эта статья , наконец, указала мне правильное направление ... но это не помогло мне полностью, так как отладчик React не будет работать с приложением, отображаемым на сервере.

ТамЕсть несколько возможных решений проблемы.В моем случае самым простым решением было объединить все мои зависимости между клиентом и сервером, которые неявно удалили все избыточные экземпляры React.

Действительно надеюсь, что этот ответ поможет кому-то другому, потому что я потратил больше месяца, пытаясьотлаживать один или два раза в день в неделю.

0 голосов
/ 20 февраля 2019

Доступ к хранилищу можно получить из дочерних компонентов, если вы открываете его через контекст или через подпорки.
Вы также можете открыть его, добавив хранилище в объект окна, но это не будет хорошей практикой, поскольку каждый посетитель вВаш сайт может видеть и изменять Магазин.(это может быть полезно, если вы не заботитесь о безопасности хранилища приращений).
Вы также можете использовать установщик, как предложено в этом ответе: Глобальное значение состояния Redux

Поставщик излишков делает магазин доступным для всех детей через контекст.

Этот тег Provider отображает ваш родительский компонент, назовем его компонентом App, который, в свою очередь, отображает все остальные компоненты внутри приложения.

Вот ключевая часть, когда мы переносимКомпонент с функцией connect (), функция connect () ожидает увидеть некоторый родительский компонент в иерархии с тегом Provider.

Нарушение инварианта: не удалось найти «store» влибо контекст, либо реквизиты «Connect (SportsDatabase)»

Итак, согласно связанному ответу, ваш домашний компонент должен иметь поставщика или хранилище в своем контексте, что может быть причинойтвоя ошибка

...