【问题标题】:Unable to pass props in Next无法在 Next 中传递道具
【发布时间】:2020-07-21 12:41:06
【问题描述】:

我正在使用 Next Js (React SSR) 制作服务器端渲染应用程序。

Index.js(只需在索引中调用另一个组件Layout)

import Layout from "./layout";
import React from "react";

class Home extends React.Component {
  render() {
    return (
      <div>
        <Layout />
      </div>
    );
  }
}

export default Home;

Layout.js

import React from "react";
import Product from "./product";

class Layout extends React.Component {
  static async getInitialProps() {
    const res = await fetch("https://api.github.com/repos/developit/preact");
    console.log(res);
    const json = await res.json();
    return { stars: json.stargazers_count };
  }

  componentDidMount() {
    if (localStorage.getItem("userLoggedIn")) {
      //Get products details for logged in user api
      //For now let us consider the same api
      // const res = fetch("https://api.github.com/repos/developit/preact");
      // const json = res.json(); // better use it inside try .. catch
      // return { stars: json.stargazers_count };
    } else {
      // Get product details for guest user api
      //For now let us consider the same api
      // const res = fetch("https://api.github.com/repos/developit/preact");
      // const json = res.json(); 
      // return { stars: json.stargazers_count };
    }
  }

  render() {
    return (
      <div>
        This is layout page
        <Product stars={this.props.stars} />
      </div>
    );
  }
}

export default Layout;

完整的简单应用示例在这里https://codesandbox.io/s/nextjs-getinitialprops-748d5

我的问题是,我正在尝试将道具从 layout 页面传递到 product 页面,并且道具是从 getInitialProps (SSR) 接收的。但是您可以在提供的示例中看到,道具没有t 工作,它仍然为this.props.stars 提供 undefined

如果我将此代码移动到 componentDidMount 并使用 setState 并将状态作为道具传递将起作用,但不会在视图页面源中显示从 api 获取的数据。

注意:请不要将此逻辑移动到它工作的 index.js 文件中,但在我的实际应用程序中它是动态路由页面,我将根据获取的查询参数获取 api页面。

如果您进入此链接https://748d5.sse.codesandbox.io/ 并单击ctrl + u,那么您会看到我还需要从 api 获取的动态内容的来源。

为了实现这个动态内容(在这个例子中是星号)只在视图源中显示,我正在做所有这些都是为了 SEO 目的。

【问题讨论】:

    标签: javascript reactjs next.js server-side-rendering


    【解决方案1】:

    简而言之,您不能从子组件调用getInitialPropsgetInitialProps caveats

    getInitialProps 不能在子组件中使用,只能在每个页面的默认导出中使用

    您的Layout 页面是Home 的子组件。

    如果您想调用getInitialProps,那么您需要在Home 页面内定义getInitialProps,或者创建一个调用自己的getInitialProps 的包装器组件,该组件将包装页面的default export PageComponet使用这个包装器组件:export default withStarsData(PageComponent);结果,这个包装器组件将传递PageComponent 一些props

    如果你想让这个函数灵活/动态,那么使用ctxquery参数和dynamic route

    这是一个理解起来相当复杂的解决方案,但简而言之,它允许主页 (/) 和布局 (/layout) 页面获取相同的数据。如果您不想多次获取数据,而是获取一次然后在页面之间共享,那么您将需要使用更高阶的状态提供程序,例如 redux

    工作示例


    components/withStars/index.js

    import React from "react";
    import fetch from "isomorphic-unfetch";
    
    // 1.) this function accepts a page Component and...
    const withStars = WrappedComponent => {
    
      // 7.) if stars data is present, returns <WrappedComponent {...props} /> with props
      // else if there's an error, returns the error
      // else returns a "Loading..." indicator
      const FetchStarsData = props =>
        props.stars ? (
          <WrappedComponent {...props} />
        ) : props.error ? (
          <div>Fetch error: {props.error} </div>
        ) : (
          <div>Loading...</div>
        );
    
      // 3.) this first calls the above function's getInitialProps
      FetchStarsData.getInitialProps = async ctx => {
    
        // 4.) here's where we fetch "stars" data
        let stars;
        let error;
        try {
          const res = await fetch("https://api.github.com/repos/developit/preact");
          const json = await res.json();
          stars = json.stargazers_count;
        } catch (e) {
          error = e.toString();
        }
    
        // 5.) optionally this will call the <WrappedComponent/> 
        // getInitialProps if it has been defined
        if (WrappedComponent.getInitialProps)
          await WrappedComponent.getInitialProps(ctx);
    
        // 6.) this returns stars/error data to the FetchStarsData function above
        return { stars, error };
      };
    
      // 2.) ...returns the result of the "FetchStarsData" function
      return FetchStarsData;
    };
    
    export default withStars;
    

    【讨论】:

    • 感谢您提供如此详细的答案。真的为得到一个好的答案而苦苦挣扎了很长时间,感谢您。感谢您的时间和通过沙盒的工作示例。我将在我的实际项目中实施,如果有任何疑问,我会回复您。。
    • 您的回答对我也有很大帮助!如何使用来自 json 的数据制作地图?使用 github 存储库 API 示例,我需要获取所有名称和 id 并将它们打印在我的索引页面和配置文件上
    • 您的示例代码的主要问题是 data 属性最初是未定义的,因为它是异步定义的(这意味着需要时间来解决请求并将 data 定义为 @987654346 @)。正因为如此,您不能在 undefined 变量上使用 map。解决方案是conditionally renderdata。在您的情况下,当data &amp;&amp; data.length &gt; 0(数据已定义且长度大于0)时,您将有条件地map 超过data
    • 嗯,完美!我会尝试!谢谢!!
    • 示例here
    猜你喜欢
    • 2022-01-14
    • 2018-06-28
    • 2020-05-09
    • 2019-08-09
    • 2014-11-19
    • 2020-12-21
    • 2020-04-07
    • 2020-10-19
    • 1970-01-01
    相关资源
    最近更新 更多