reactjs - เป็นไปได้ไหมที่จะทำการเปลี่ยนเส้นทางฝั่งเซิร์ฟเวอร์พร้อมการปรับตัวระหว่างประเทศใน Next.js?
ดังนั้นฉันมีแอป Next.js ขนาดเล็ก ซึ่งมีหน้าเพียงสำหรับผู้ใช้ที่ล็อกอินแล้ว ไม่มีอะไรพิเศษที่นั่น เพื่อจัดการเส้นทางที่ต้องมีการยืนยันตัวตน ฉันเขียน HOC (เรียกว่า withAuth) ที่จะเปลี่ยนเส้นทางบนเซิร์ฟเวอร์ เพื่อหลีกเลี่ยงการกระพริบของหน้าบนฝั่งลูกค้า มันทำงานได้ดีจนถึงตอนนี้ แต่ฉันมีปัญหาว่าแอปของฉันรองรับหลายภาษา ดังนั้นในปัจจุบันผู้ใช้จะถูกเปลี่ยนเส้นทางไปยังหน้าล็อกอินในภาษาปริยาย (ภาษาอังกฤษ) แต่ฉันต้องการให้เก็บภาษาที่ผู้ใช้เลือกไว้
โชคไม่ดีที่ useRouter() ใช้ได้เฉพาะบนฝั่งไคลเอนต์ ดังนั้นวิธีแรกของฉันจึงไม่สำเร็จ (ฉันควรรู้ดีกว่านี้) นี่คือโค้ดของฉัน:
auth.tsx
import redirect from "../utils/redirect";
import * as React from "react";
import { sendData } from "../utils/sendRequest";
export const withAuth = <T extends object>(C: React.ComponentClass<T>) => {
return class AuthComponent extends React.Component<T> {
static async getInitialProps({...ctx}: NextPageContext) {
await sendData('GET','/user').then(response => {
if (!response || !response.success) {
redirect(ctx, "/login");
return {
user: null,
};
}else return {
user: response.user,
};
}).catch(err=>{console.error(err)})
}
render() {
return <C {...this.props} />;
}
};
};
redirect.ts
import Router, {useRouter} from "next/router";
const redirect = (context: any, target: string) => {
let lang = "";
/*if(!(useRouter.locale == "en")){
lang = "/"+useRouter.locale; This wont work
}*/
if (context.res) {
context.res.writeHead(303, { Location: /*lang+*/target });
context.res.end();
} else {
Router.replace(/*lang+*/target);
}
};
export default redirect;
โปรไฟล์.tsx
import * as React from "react";
import { withAuth } from "../components/auth";
//...
class ProfileClass extends React.PureComponent<{}> {
render() {
return <Profile />;
}
}
export default withAuth(ProfileClass);
ฉันรู้สึกขอบคุณสำหรับทุกไอเดียที่จะแก้ปัญหานี้ :) ขอบคุณ!
คำตอบ #1
วิธีแก้ปัญหาด้วย getInitialProps ในหน้า _app
คุณสามารถเข้าถึงอินสแตนซ์ของ router จากออบเจ็กต์ context ของ getInitialProps ซึ่งสามารถเข้าถึง locale ปัจจุบันได้ โปรดทราบว่าออบเจ็กต์ router จะสามารถใช้ได้เฉพาะกับ context ที่ส่งไปยัง _app ของ getInitialProps เท่านั้น แต่จะไม่สามารถใช้ได้กับ context ที่ส่งไปยังหน้าอื่น ๆ
// pages/_app.tsx
static async getInitialProps({ router, ctx }: NextPageContext) {
const lang = router.locale;
await sendData('GET','/user').then(response => {
if (!response || !response.success) {
redirect(ctx, `${lang}/login`);
return {
user: null,
};
} else {
return {
user: response.user,
};
}
}).catch(err => { console.error(err) })
}
วิธีแก้ปัญหาด้วย getServerSideProps สำหรับหน้าต่าง ๆ
เนื่องจากไม่สามารถเข้าถึงข้อมูล locale จากหน้าที่ใช้ getInitialProps ได้ คุณสามารถใช้ getServerSideProps แทน การทำเช่นนี้เกี่ยวข้องกับการปรับโครงสร้างตรรกะที่มีอยู่ให้เข้ากับการใช้งาน getServerSideProps
ก่อนอื่น เราจะนำ withAuth มาใช้ใหม่และแยกตรรกะสำหรับการดึงผู้ใช้ ซึ่งจะเพิ่มวัตถุ user ไปยัง context และส่งต่อไปยัง getServerSideProps
// /components/auth
export function withAuth(gssp) {
return async (context: GetServerSidePropsContext) => {
try {
const response = await sendData("GET", "/user");
if (response && response.success) {
// Add user to context to be used in `getServerSideProps`
context = { ...context, user: response.user };
}
} catch (err) {
console.error(err);
}
return await gssp(context); // Pass `context` and continue on to call `getServerSideProps`
};
}
จากนั้น withAuth สามารถใช้เพื่อห่อฟังก์ชัน getServerSideProps ในหน้าของคุณ ซึ่งการเปลี่ยนเส้นทางจะเกิดขึ้นหาก user ไม่ได้ถูกตั้งค่า
import * as React from "react";
import { withAuth } from "../components/auth";
export const getServerSideProps: GetServerSideProps = withAuth(async (context: : GetServerSidePropsContext) => {
if (!context.user) {
return {
redirect: {
destination: `/${context.locale}/login`,
statusCode: 303
}
};
}
return {
props: {
user: context.user
}
};
});
class ProfileClass extends React.PureComponent<{}> {
render() {
return <Profile />;
}
}
export default ProfileClass;
