Доступ к потребляемому React.Context в Next.js getInitialProps с использованием HOC - PullRequest
0 голосов
/ 15 февраля 2019

Я пытаюсь абстрагировать свои вызовы API с помощью простого сервиса, который предоставляет очень простой метод, который является просто HTTP-вызовом.Я храню эту реализацию в React Context и использую ее провайдера внутри моего _app.js, так что API доступен глобально, но у меня есть проблема с фактическим использованием контекста на моих страницах.

pages / _app.js

import React from 'react'
import App, { Container } from 'next/app'

import ApiProvider from '../Providers/ApiProvider';

import getConfig from 'next/config'
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig()

export default class Webshop extends App 
{
    static async getInitialProps({ Component, router, ctx }) {
        let pageProps = {}

        if (Component.getInitialProps) {
            pageProps = await Component.getInitialProps(ctx)
        }

        return { pageProps }
    }

    render () {
        const { Component, pageProps } = this.props

        return (
            <Container>
                <ApiProvider endpoint={publicRuntimeConfig.api_endpoint}>
                    <Component {...pageProps} />
                </ApiProvider>
            </Container>
        );
    }
}

Услуги / Api.js

import fetch from 'unfetch'

function Api (config)
{
    const apiUrl = config.endpoint;

    async function request (url) {
        return fetch(apiUrl + '/' + url);
    };

    this.decode = async function (code) {
        const res = request('/decode?code=' + code);
        const json = await res.json();
        return json;
    }

    return this;
}

export default Api;

Поставщики / ApiProvider.js

import React, { Component } from 'react';
import Api from '../Services/Api';

const defaultStore = null;

class ApiProvider extends React.Component
{
    state = {
        api: null
    };

    constructor (props) {
        super(props);

        this.state.api = new Api({ endpoint: props.endpoint });
    }

    render () {
        return (
            <ApiContext.Provider value={this.state.api}>
                {this.props.children}
            </ApiContext.Provider>
        );
    }
}

export const ApiContext = React.createContext(defaultStore);
export default ApiProvider;
export const ApiConsumer = ApiContext.Consumer;
export function withApi(Component) {
    return function withApiHoc(props) {
        return (
            <ApiConsumer>{ context => <Component {...props} api={context} /> }</ApiConsumer>
        )
    }
};

страниц / code.js

import React, { Component } from 'react';
import Link from 'next/link';
import { withApi } from '../Providers/ApiProvider';

class Code extends React.Component
{
    static async getInitialProps ({ query, ctx }) {
        const decodedResponse = this.props.api.decode(query.code); // Cannot read property 'api' of undefined

        return {
            code: query.code,
            decoded: decodedResponse
        };
    }

    render () {
        return (
            <div>
                [...]
            </div>
        );
    }
}

let hocCode = withApi(Code);
hocCode.getInitialProps = Code.getInitialProps;
export default hocCode;

Проблема в том, что я не могу получить доступ к используемому контексту.Я мог бы просто сделать прямой fetch вызов внутри моего getInitialProps, однако я хотел абстрагировать его, используя небольшую функцию, которая также принимает настраиваемый URL.

Что я делаю не так?

1 Ответ

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

Вы не можете получить доступ к экземпляру вашего провайдера в виде статического метода getInitialProps, он был вызван еще до того, как сгенерировано дерево React (когда ваш провайдер доступен).

Я бы посоветовал вам сохранить API Singelton of you в модуле API и использовать его в методе getInitialProps с помощью обычного импорта.

Или вы можете вставить его в свой componentPage внутри _appgetInitialProps, что-то вроде этого:

// _app.jsx
import api from './path/to/your/api.js';

export default class Webshop extends App {
    static async getInitialProps({ Component, router, ctx }) {
        let pageProps = {}
        ctx.api = api;

        if (Component.getInitialProps) {
            pageProps = await Component.getInitialProps(ctx)
        }

        return { pageProps }
    }

    render () {
        const { Component, pageProps } = this.props

        return (
            <Container>
                <Component {...pageProps} />
            </Container>
        );
    }
}

// PageComponent.jsx

import React, { Component } from 'react';

class Code extends React.Component
{
    static async getInitialProps ({ query, ctx }) {
        const decodedResponse = ctx.api.decode(query.code); // Cannot read property 'api' of undefined

        return {
            code: query.code,
            decoded: decodedResponse
        };
    }

    render () {
        return (
            <div>
                [...]
            </div>
        );
    }
}

export default Code;

Имеет ли это для вас смысл?

...