Next JS布局组件,向子组件传递props

15

我找到了一个代码来解决Next JS在更改页面时重新渲染的问题,但现在我需要将props发送到子组件。我不知道如何在这里使它起作用,这是我的layout.js代码。正如你所看到的,我可以将props发送到Header组件,但对于子组件,因为它是一个变量而不是组件,我不知道该怎么做。

import Header from "../components/header";
import Footer from "../components/footer";
import { Fragment } from "react";

export default function Layout({ children, ...pageProps }) {
  return (
    <Fragment>
      <Header
        isRegisterPage={pageProps.isRegisterPage}
        isLoginPage={pageProps.isLoginPage}
        outHome={pageProps.outHome}
      />
      {children}
      <Footer />
    </Fragment>
  );
}

感谢您的帮助


1
这是redux(本质上是带有良好开发工具的React Context)发挥作用的场景 - 维护一个全局状态变量,通过React Context和useSelector被任何想要使用它的组件使用,而不是通过prop drilling。 - Adam Jenkins
4个回答

5
你有考虑过使用React的上下文API吗?这个想法是,当使用上下文API时,你的组件状态会被提升,以便在全局范围内进行管理。如果一个组件需要一个prop,而不是手动地向下传递props(prop drilling),你可以简单地将你的组件包装在所谓的上下文提供者中。这将允许该组件访问你应用程序的全局状态。这很好,因为当你的应用程序变得更大时,你可能需要通过许多组件传递props,这会使代码混乱并增加不必要的困惑。
React提供了一些很棒的文档来设置你的React应用程序以使用上下文API。强烈建议查看! https://reactjs.org/docs/context.html

2
我不喜欢这个解决方案,因为它将组件耦合在一起。如果您有一些通用组件想要作为子组件,但是您也在应用程序的其他部分中使用它,在那里您需要的上下文(当它是子组件时)在应用程序的其他部分中不适用,该怎么办? - nikk wong
1
使用上下文是一个相当具有个人观点的设计决策。 - gutscdav000
使用zustand的应用路由器来持久化并设置客户端的全局状态,针对Next.js 13.4版本。 - darren z

2

试试这个

import Header from "../components/header";
import Footer from "../components/footer";
import { Fragment } from "react";

export default function Layout({ children, ...pageProps }) {

  function recursiveMap(children, fn) {
    return React.Children.map(children, child => {
      if (!React.isValidElement(child) || typeof child.type == 'string') {
        return child;
      }
  
      if (child.props.children) {
        child = React.cloneElement(child, {
          children: recursiveMap(child.props.children, fn)
        });
      }
  
      return fn(child);
    });
  }

  // Add props to all child elements.
  const childrenWithProps = recursiveMap(children, child => {
    // Checking isValidElement is the safe way and avoids a TS error too.
    if (isValidElement(child)) {
      // Pass additional props here
      return cloneElement(child, { currentUser: { ...user } })
    }

    return child;
  });

  return (
    <Fragment>
      <Header
        isRegisterPage={pageProps.isRegisterPage}
        isLoginPage={pageProps.isLoginPage}
        outHome={pageProps.outHome}
      />
      {childrenWithProps}
      <Footer />
    </Fragment>
  );
}

4
嗨,Akshit,欢迎来到 Stack Overflow!你为这个问题提供了一个很好的解决方案,但是请尝试给出解释,说明为什么这个解决方案有效,以便 Joangel 和其他阅读你答案的人也能够理解解决方案。特别是对于那些没有完全相同代码但面临类似问题的人来说,这将非常有用。 - Axel Köhler

2
您可以使用React的cloneElement来实现这一点。
React.cloneElement(children, {
    isRegisterPage: pageProps.isRegisterPage,
    isLoginPage: pageProps.isLoginPage,
    outHome: pageProps.outHome
})

在您的情况下,以下是一个完整的示例:

import Header from "../components/header";
import Footer from "../components/footer";
import React, { Fragment } from "react";

export default function Layout({ children, ...pageProps }) {
  return (
    <Fragment>
      <Header
        isRegisterPage={pageProps.isRegisterPage}
        isLoginPage={pageProps.isLoginPage}
        outHome={pageProps.outHome}
      />
      {
          React.cloneElement(children, {
              isRegisterPage: pageProps.isRegisterPage,
              isLoginPage: pageProps.isLoginPage,
              outHome: pageProps.outHome
          })
      }
      <Footer />
    </Fragment>
  );
}

-1
从Lucas Raza的答案中,以下是一个使用Context API将主题应用于不同组件的示例。
1.创建上下文文件。
//ThemeContex.js
import { createContext, useState } from "react";

export const ThemeContext = createContext();

export const withThemeContext = Component => {
    const WrappedComp = props => {
  
        const [darkColor,lightColor] = ["#3b3b3b", "#ddd"]
        const [lightBackgoround,darkBackgoround] = ["#ececec","#1d2a35"]       

        const darkTheme = {
            backgroundColor: darkBackgoround,
            color:lightColor,
        }

        const lightTheme = {
            backgroundColor: lightBackgoround,
            color:darkColor,
        }

        const themes = {
            darkTheme, lightTheme
        }
    
        const [theme, setTheme] = useState(lightTheme)

    
        const children ={
            theme,
            themes, 
            setTheme,
        }
    
        return(
            <StylesContext.Provider value={{...children}} >
                <Component {...props} />    
            </StylesContext.Provider>
        )
    }
    
    return WrappedComp;
}
  • 在 _app.js 中,使用 withThemeContext 高阶组件进行导入,并在导出时将 MyApp 包装起来。

     import { withThemeContext } from '../components'
    
     function MyApp({ Component, pageProps }) {
           return <Component {...pageProps} />
     }
    
     export default withThemeContext(MyApp)
    
  • 现在你可以在组件中的任何地方使用主题了。

     import { useContext } from 'react'
     import {ThemeContext} from '../components'
    
     export default function Home() {
         const { theme } =useContext(ThemeContext)
    
         return (
             <div id="home" style={theme}>            
                 // Home logic...
             </div>
         )
     }
    

  • 网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接