I have this HOC line of code from withUser.tsx. When a user is authenticated, the authenticated pages will then be wrapped by it so that the specified user-role will be the one to only have access to pages intended.
import axios, { AxiosError } from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";
const withUser = (Page: any) => {
const WithAuthUser = (props: any): JSX.Element => <Page {...props} />;
WithAuthUser.getInitialProps = async (context: any): Promise<any> => {
const token = getCookie("token", context.req);
let user = null;
let userLinks = [];
if (token) {
try {
const response = await axios.get(`${API}/user`, {
headers: {
authorization: `Bearer ${token}`,
contentType: "application/json",
},
});
console.log("Response in withUser: ", response);
user = response.data.user;
userLinks = response.data.links;
} catch (err: unknown) {
const error = err as AxiosError;
if (error.response?.status === 401) {
user = null;
}
}
}
if (user === null) {
// redirect
context.res.writeHead(302, {
Location: "/",
});
context.res.end();
} else {
return {
...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
user,
token,
userLinks,
};
}
};
return WithAuthUser;
};
export default withUser;
Now, the above code is not my final writing of TypeScript, I could be wrong but this is how I converted it from JS, please feel free to give me a refactored TSX codes here, here is the JS version:
import axios from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";
const withUser = (Page) => {
const WithAuthUser = (props) => <Page {...props} />;
WithAuthUser.getInitialProps = async (context) => {
const token = getCookie("token", context.req);
let user = null;
let userLinks = [];
if (token) {
try {
const response = await axios.get(`${API}/user`, {
headers: {
authorization: `Bearer ${token}`,
contentType: "application/json",
},
});
console.log("Response in withUser: ", response);
user = response.data.user;
userLinks = response.data.links;
} catch (error) {
if (error.response.status === 401) {
user = null;
}
}
}
if (user === null) {
// redirect
context.res.writeHead(302, {
Location: "/",
});
context.res.end();
} else {
return {
...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
user,
token,
userLinks,
};
}
};
return WithAuthUser;
};
export default withUser;
But now, when using it when an Authenticated /user page, I could not get any data from the user. It will give me an undefined and for example, user.first_name will not be shown:
import withUser from "../withUser";
const User = ({ user }: any): JSX.Element => (
<div className="flex min-h-screen flex-col items-center justify-center">
{user.first_name}
</div>
);
export default withUser(User);
Any correct ways of implementing this would be very much appreciated. Thanks!
CodePudding user response:
Whether you are in Reactjs or Nextjs, I think there needs to have a correct type definitions of your HOC component in the first place.
First you need to define your HOC component as a React.ComponentType:
const withUser = (ChildComp: React.ComponentType<any | string>) => { /* code follows */ }
you also need to define an interface for the expected values for these"
const token = getCookie("token", context.req);
let user = null;
let userLinks = [];
and when you wrap your child component, say user.tsx, do it like this:
type UserType = {
first_name: string
}
const User: React.SFC<ContainerProps> = ({ user}: UserType)=> (
<h1>{user.first_name ?? "User not found"}</h1>
);
export default withUser(User);
You can read more about here: Create a TypeScript HOC in React
CodePudding user response:
Okay, sorry this was just a bug and I figure out that I did not have any userLinks from the REST API that I was passing in. So I can already consider this question as resolved as I have already fixed it.
Here is the code of my fix:
import axios, { AxiosError } from "axios";
import { API } from "../config";
import { getCookie } from "../helpers/auth";
const withUser = (Page: any) => {
const WithAuthUser = (props: any): JSX.Element => <Page {...props} />;
WithAuthUser.getInitialProps = async (context: any): Promise<any> => {
const token = getCookie("token", context.req);
console.log("token: ", token);
let user = null;
if (token) {
try {
const response = await axios.get(`${API}/user`, {
headers: {
authorization: `Bearer ${token}`,
contentType: "application/json",
},
});
console.log("response: ", response);
user = response.data;
} catch (err: unknown) {
const error = err as AxiosError;
if (error.response?.status === 401) {
user = null;
}
}
}
if (user === null) {
// redirect
context.res.writeHead(302, {
Location: "/",
});
context.res.end();
} else {
return {
...(Page.getInitialProps ? await Page.getInitialProps(context) : {}),
user,
token,
};
}
}
return WithAuthUser;
}
export default withUser;