nextjs app router utils.js
Unanswered
Varun posted this in #help-forum
VarunOP
I am making a utils.js and I put it in my src/app directory. if i try importing next/headers
Error:
× You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.
what could this utils files parents be that next is complaining about?
Error:
× You're importing a component that needs next/headers. That only works in a Server Component but one of its parents is marked with "use client", so it's a Client Component.
what could this utils files parents be that next is complaining about?
23 Replies
Giant Angora
If you import
Just create a separate file for server-side utilities that use stuff like
next/headers you can only import utils.js into Server Components, you are probably importing utils.js in a Client Component. Just create a separate file for server-side utilities that use stuff like
next/headers@Giant Angora If you import `next/headers` you can only import `utils.js` into Server Components, you are probably importing `utils.js` in a Client Component.
Just create a separate file for server-side utilities that use stuff like `next/headers`
American Crow
^ this and consider using 'server-only' package to avoid those errors and to get a better error message
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment
https://nextjs.org/docs/app/building-your-application/rendering/composition-patterns#keeping-server-only-code-out-of-the-client-environment
@Giant Angora If you import `next/headers` you can only import `utils.js` into Server Components, you are probably importing `utils.js` in a Client Component.
Just create a separate file for server-side utilities that use stuff like `next/headers`
VarunOP
// In your page component file
import CreateNewDraft from './draftIdEditClient';
import { getTokens } from 'next-firebase-auth-edge/lib/next/tokens';
import { cookies } from 'next/headers';
import { authConfig } from '../../../../config/server-config';
import { toUser } from '../../../../components/user';
import withSubscription from '../../../../subWrapper';
function DraftEditPage({ uid, params }) {
// Now, this component directly receives all the necessary props.
return <CreateNewDraft uid={uid} params={params} />;
}
export const getServerSideProps = async ({ params }) => {
const tokens = await getTokens(cookies(), authConfig);
const userInfo = toUser(tokens);
return {
props: {
uid: userInfo.email,
params,
},
};
};
// Here you apply the subscription HOC
export default withSubscription(DraftEditPage, ['premium', 'enterprise']);I am tryna do getServerSideProps but im using app router so its not letting me. i tried reading the docs but am a bit confused on how I can do this
any ideas?
Giant Angora
Prolly better to submit another question as its not related
VarunOP
// hoc/withSubscription.js
import React from 'react';
import { useRouter } from 'next/navigation';
import { getSubscriptionByEmail } from './components/utils';
import { getUserEmailFromCookies } from './server_utils';
const withSubscription = async (WrappedComponent, allowedPlans) => {
return async (props) => {
const uid = await getUserEmailFromCookies();
const currentUserPlan = await getSubscriptionByEmail(uid);
const router = useRouter();
if (!allowedPlans.includes(currentUserPlan)) {
useEffect(() => {
router.push('/webapp/pricing');
}, []);
return null; // Or a loading indicator
}
return <WrappedComponent {...props} />;
};
};
export default withSubscription;@Varun javascript
// hoc/withSubscription.js
import React from 'react';
import { useRouter } from 'next/navigation';
import { getSubscriptionByEmail } from './components/utils';
import { getUserEmailFromCookies } from './server_utils';
const withSubscription = async (WrappedComponent, allowedPlans) => {
return async (props) => {
const uid = await getUserEmailFromCookies();
const currentUserPlan = await getSubscriptionByEmail(uid);
const router = useRouter();
if (!allowedPlans.includes(currentUserPlan)) {
useEffect(() => {
router.push('/webapp/pricing');
}, []);
return null; // Or a loading indicator
}
return <WrappedComponent {...props} />;
};
};
export default withSubscription;
Giant Angora
this is a Client Component and should have a "use client" directive as it has
useRouter and useEffect@Varun its server_utils here
yeah you can't use
headers() function in client componentVarunOP
what are some ways I can work around that then?
@Varun what are some ways I can work around that then?
firebase-auth?
VarunOP
yea i use firebase auth
but subscriptions managed by stripe
have you checked their example repo?
VarunOP
yea all my auth stuff works fine with the cookies and stuff but I ran into problems when trying to incorporate stripe subscriptions into my app. I get their subscription by calling a getSubscription function with their email
maybe I should include subscription in my context that includes the email
like create a route handler or server action for the subscription
'use server'
import { getTokens } from 'next-firebase-auth-edge/lib/next/tokens';
import { cookies } from 'next/headers';
export async function getSubscriptionByEmail() {
const tokens = await getTokens(cookies(), authConfig);
const userInfo = toUser(tokens);
const currentUserPlan = await getSubscriptionByEmail(userInfo.uid);
return { currentUserPlant }
}VarunOP
ok cool ill look into route handlers
thanks
VarunOP
yea I just aded it to my user object and it worked instead of treating as 2 seperate entities and added checks in my middleware,.js instead of the component wrapper
thanks!