组件在父逻辑完成之前渲染 props.children

时间:2021-07-25 13:58:56

标签: reactjs next.js

我正在尝试自学 next.js,但我遇到了一些身份验证逻辑问题。

我有一个页面 protected/profile,如果用户没有登录,我想阻止他们访问。为了检查这一点,我正在通过 getServerSideProps 检索一些用户数据,然后我试图将返回的用户数据传递给组件,然后组件将其传递给名为 Protected 的子元素。 Protected 是执行逻辑来检查用户是否登录,如果用户登录,则应通过返回 props.children 来显示个人资料页面。

如果用户没有登录,他们应该被重定向到 /

然而,看起来配置文件组件只是渲染配置文件页面,而不是等待受保护的逻辑完成。如果我在注销时尝试访问个人资料页面,我会收到一条错误消息,提示找不到 user.user_metadata,而实际上我应该被重定向。

控制台日志最终是

Profile log
protected.tsx:7 Protected log
protected.tsx:17 Protected: Has user
const Profile = ({user} : {user: User}) => {
    console.log("Profile log");
    return (
        <Protected user={user}>
            <h1>This is Profile</h1>
            <h1>Hello, {user.user_metadata.full_name}!</h1>
            <p> Your email : {user.email}</p>
        </Protected>
    )
}

export const getServerSideProps: GetServerSideProps = async ({req}) => {
    const {user} = await supabaseClient.auth.api.getUserByCookie(req);
    return { props: {user: user}}
}

export default Profile;
export default function Protected(props: {user: User, children}){
    console.log("Protected log");
    if(!props.user){
        console.log("Protected: Null user");
        return {
            redirect: {
                destination: "/",
                permanent: false
            }
        }
    }
    console.log("Protected: Has user");
    return props.children;
}

1 个答案:

答案 0 :(得分:0)

所以,首先,正如我在评论中所说,你不能从 React 组件返回 redirect 对象,这是行不通的。如果您想使用 redirect 对象,您需要从 getServerSideProps 返回它。或者使用 useRouter 或类似的东西制作一些自定义逻辑。

其次,您应该输入 user 作为可选,因为它可能不存在(根据您的代码):

const Profile = ({user} : {user?: User}) => {
    console.log("Profile log");
    return (
        <Protected user={user}>
            <h1>This is Profile</h1>
            <h1>Hello, {user.user_metadata.full_name}!</h1>
            <p> Your email : {user.email}</p>
        </Protected>
    )
}

现在您将看到 Typescript 错误,您正在尝试从可能未定义的对象访问属性。

您可以做的是使用用户逻辑制作单独的组件:

const Profile = ({user} : {user?: User}) => {
    console.log("Profile log");
    return (
        <Protected user={user}>
            <UserProfile user={user} />
        </Protected>
    )
}

或让Protected接受children as a function

const Profile = ({ user }: { user?: User }) => {
  console.log('Profile log');
  return (
    <Protected user={user}>
      {() => (
        <>
          <h1>This is Profile</h1>
          <h1>Hello, {user.user_metadata.full_name}!</h1>
          <p> Your email : {user.email}</p>
        </>
      )}
    </Protected>
  );
};

Protected 大致如下所示:

export function Protected(props) {
  if(!props.user){
    // Make some other redirect logic, you current implementation with object won't work
  }
  // Notice here we calling the children
  return props.children();
}