使用 HOC 在 Next.js getInitialProps 中访问使用的 React.Context
Posted
技术标签:
【中文标题】使用 HOC 在 Next.js getInitialProps 中访问使用的 React.Context【英文标题】:Accessing consumed React.Context in Next.js getInitialProps using HOC 【发布时间】:2019-07-09 14:17:13 【问题描述】:我正在尝试使用一个简单的服务来抽象我的 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;
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 的小函数来抽象它。
我做错了什么?
【问题讨论】:
我在尝试使用Context.Consumer
API 访问功能组件中的上下文时遇到了类似的问题。您是否尝试过使用static contextType = ApiContext
将其转换为类组件。不是一个解决方案,但它会帮助你找出这是否是问题
探测的是 getInitialProps 是一个静态方法,因此你不能从它里面访问类实例属性
@ShubhamKhatri 哦,对了……这太明显了。那我怎么能做这样的事情呢?我需要将它作为我的 HOC 的 getInitialProps 的参数传递,对吗?这也是我尝试过的,但是我无法以编程方式访问 React.Context 数据,如果我用消费者上下文包装我的组件,getInitialProps 将不会被正确调用。
【参考方案1】:
您无法以 static 方法 getInitialProps
访问您的提供者的实例,它在 React 树生成之前被调用(当您的提供者可用时)。
我建议您将 API 的 Singelton 保存在 API 模块中,并通过常规导入在 getInitialProps
方法中使用它。
或者,您可以将其注入到 _app
getInitialProps 内的 componentPage 中,类似这样:
// _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;
这对你有意义吗?
【讨论】:
所以你建议不要使用 React.Context,而是使用单例方法? 是的,singelton 可以注入到我建议的所有页面组件中。 这样我什至可以只在我需要的地方准确地导入它,而不是全局注入它,对吧?以上是关于使用 HOC 在 Next.js getInitialProps 中访问使用的 React.Context的主要内容,如果未能解决你的问题,请参考以下文章
在 Next.js 中创建一个 HOC(高阶组件)进行身份验证