使用HOC访问Next.js getInitialProps中消耗的React.Context [英] Accessing consumed React.Context in Next.js getInitialProps using HOC

查看:111
本文介绍了使用HOC访问Next.js getInitialProps中消耗的React.Context的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过使用一种简单的服务来抽象我的API调用,该服务提供了一种非常简单的方法,它只是一个HTTP调用.我将此实现存储在React Context中,并在我的_app.js中使用其提供程序,以便该API在全球范围内可用,但是在实际使用我的页面中的上下文时遇到了问题.

I am attempting to abstract my API calls by using a simple service that provides a very simple method, which is just an HTTP call. I store this implementation in a React Context, and use its provider inside my _app.js, so that the API is globally available, but I have a problem at actually consuming the context in my 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;

Providers/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>
        )
    }
};

pages/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;

问题是我无法访问消耗的上下文.我可以直接在getInitialProps中进行直接fetch调用,但是我想通过使用也需要可配置URL的小函数来对其进行抽象.

The problem is that I am unable to access the consumed context. I could just make a direct fetch call within my getInitialProps, however I wanted to abstract it by using a small function that also takes a configurable URL.

我在做什么错了?

推荐答案

您不能以 static 方法getInitialProps的方式访问提供程序的实例,该方法在React树之前被调用(当您的提供程序可用时).

You can't access an instance of your provider in as static method getInitialProps, it was called way before the React tree is generated (when your provider is available).

我建议您将API的 Singelton 保存在API模块中,并通过常规导入在getInitialProps方法内使用它.

I would suggest you to save an Singelton of your API in the API module, and consume it inside the getInitialProps method via regular import.

或者,您可以将其注入到_app getInitialProps中的componentPage中,如下所示:

Or, you can inject it to your componentPage inside the _app getInitialProps, something like that:

// _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;

这对您有意义吗?

这篇关于使用HOC访问Next.js getInitialProps中消耗的React.Context的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆