简体   繁体   English

服务器端在 React 中使用 Next.js 加载全局组件

[英]Server side load a global component with Next.js in React

The fact that I can't find anyone asking this question probably means that I'm not understanding something fully or I'm searching with the wrong keywords so please don't bite my head off if this is a stupid question.我找不到任何人问这个问题的事实可能意味着我没有完全理解某些东西或者我正在使用错误的关键字进行搜索,所以如果这是一个愚蠢的问题,请不要咬我的头。

I'm pasting the relevant parts of the code but if you want a repo of the full example, here it is .我正在粘贴代码的相关部分,但如果您想要完整示例的存储库,这里是. The full question will be at the bottom.完整的问题将在底部。


Here's my folder structure:这是我的文件夹结构:

server.js
/components
    Layout.js
/pages
    contact.js

server.js

// tells next which page to load
server.get("/contact/:id", (req, res) => {
    const actualPage = "/contact"
    const queryParams = {id: req.params.id}
    app.render(req, res, actualPage, queryParams)
})

// api uri for grabbing contacts from the database
server.get("/api/contact/:id", (req, res) => {
    Contact.findOne({first_name: req.params.id}, (error, contact) => {
        if (error) return next(error)
        res.status(200).json(contact)
    })
})

pages/contact.js

const Contact = props => (
    <Layout>
        <h1>{props.contact.first_name} {props.contact.last_name}</h1>
    </Layout>
)

// a static async call passes fetched data into the props
Contact.getInitialProps = async function (context) {
    const {id} = context.query
    const res = await fetch(`http://localhost:3000/api/contact/${id}`)
    const contact = await res.json()
    return {contact: contact}
}

components/Layout.js

const Layout = (props) =>
<div>
    <div>
        <Link href="/contact/John">
            <a>John</a>
        </Link>
        <Link href="/contact/Jed">
            <a>Jed</a>
        </Link>
        <Link href="/contact/Fred">
            <a>Fred</a>
        </Link>
    </div>
    {props.children}
</div>

I'm trying to figure out whether or not it's possible to dynamically query the database to build a navigation of the documents in the database.我试图弄清楚是否可以动态查询数据库以构建数据库中文档的导航。 The only way I can think to do it is by re-rendering the entire navigation with every component but this seems extremely unnecessary.我能想到的唯一方法是使用每个组件重新渲染整个导航,但这似乎非常不必要。 Again, if you want to give the code a try, here's my example repo .同样,如果您想尝试一下代码,这是我的示例 repo

One of the ways I can think of is to use custom app.js and add componentDidMount method (it is fired only once) where you can fetch all the contacts, store it inside app.js state and pass it down to pages and components.我能想到的一种方法是使用自定义 app.js并添加componentDidMount方法(它只被触发一次),您可以在其中获取所有联系人,将其存储在 app.js 状态中并将其传递给页面和组件。

_app.js _app.js

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

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

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

    return { pageProps };
  }

  // store contacts in the state
  state = {
    contacts: undefined
  };

  componentDidMount() {
    // get contacts and store them in the _app.js state
    fetch('some-api/all-contacts-endpoint').then(contacts => {
       this.setState({ contacts });
    });
  }

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

    return (
      <Container>
        <Component {...pageProps} contacts={this.state.contacts} />
      </Container>
    );
  }
}

pages/contact.js页面/contact.js

// contacts will be inside props here
const Contact = props => (
  <Layout contacts={props.contacts}>
    <h1>
      {props.contact.first_name} {props.contact.last_name}
    </h1>
  </Layout>
);

// a static async call passes fetched data into the props
Contact.getInitialProps = async function(context) {
  const { id } = context.query;
  const res = await fetch(`http://localhost:3000/api/contact/${id}`);
  const contact = await res.json();
  return { contact: contact };
};

components/Layout.js组件/Layout.js

const Layout = ({ contacts = [] }) => (
  <div>
    <div>
      {contacts.map(contact => (
        <Link key={contact.id} href={`/contact/${contact.id}`}>
          <a>{contact.name}</a>
        </Link>
      ))}
    </div>
    {props.children}
  </div>
);

Hope this helps!希望这可以帮助!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM