I am trying to understand how I am supposed to share data across my components. What I am trying to do is have a auth_token saved in memory that I can share across my application. Right now, It feels like I have two options
Mixing both of these options seems to get me what I want. My issues is that my gut tells me I am doing things the wrong way.
I have a small sandbox set up for testing, where I have a few client and server components that I use to test if data is being passed around.
page.tsx
import React from 'react';
import ContextCC from "./contenxt_cc";
import ContextSC from "./context_sc";
import ContextChildCC from './context_child_cc';
const Page: React.FC = () => {
const data = "token.AWd12b112d12d11.123123123";
return (
<div>
<p> This is a server component - {data} </p>
<ContextCC data={data}>
<ContextSC data={data} />
<ContextChildCC />
</ContextCC>
</div>
);
};
export default Page;
context_cc.tsx
'use client'
import React, { useContext } from 'react';
import AppContext from './app_context';
export default function ContextCC({ children, data }: { children: React.ReactNode, data: string }) {
const sharedData = {
sharedMessage: data,
}
return (
<AppContext.Provider value={sharedData}>
<div>
<p> This is a client component - {sharedData.sharedMessage} </p>
{ children }
</div>
</AppContext.Provider>
);
}
context_sc.tsx
export default function ContextSC({data}: { data: string }) {
return (
<div>
<p> This is a server component - { data }</p>
</div>
);
}
contect_child_cc
"use client";
import { useContext } from "react";
import AppContext from "./app_context";
import { printAuthToken } from "./server_action";
import { useState } from "react";
export default function ContextChildCC() {
const [serverRes, setServerRes] = useState("");
const context = useContext(AppContext);
const action = async () => {
const result = await printAuthToken(context.sharedMessage)
setServerRes(result.msg);
}
return(
<div>
<p> This is a child client component - {context.sharedMessage} </p>
<p> {serverRes} </p>
<button onClick={action}> Send </button>
</div>
)
}
This gives me the output that I would expect. It just feels like there should be a smarter way to pass data around. Like If I have a server component that would need to pass along a auth-token I don't like having to ensure that I am passing the prop. I feel like I could easily forget to do it and brake things.
I also made a server action and I feel like this flow is better. Is the way to go just use server actions over server components? Maybe what I am trying to understand better is when to use server components over server actions over client components? This is all kinda confusing to me >,<
server_action.ts
"use server"
export async function printAuthToken(authToken: string) {
console.log(authToken);
return { msg: "This is a response from a server action - " + authToken }
}

Perhaps this mental model helps. If you write React applications with Server Components, your component tree starts by default with Server Components. This is the place where you do as much data fetching as needed for a "nice" initial render without much loading spinners. Meaning: Because a Server Components is an async function, you can just fetch data, await it, and then render JSX.
Once you need client side JavaScript, e.g. Event Handlers or Hooks (.e.g. useState) in a component, you make it a Client Component with the 'use client'; directive. Naturally your component tree becomes something like Server Components at the top and Client Components at the bottom.
Both, Server and Client Components, get rendered on the server. However, Server Components allow you also to fetch initial data on the server, but then do not allow JS driven interactions.
Eventually you want to call functions in a Client Component which invoke server-side code (e.g. deleting a Comment). Then you can give the Client Component a function that's annotated with a server directive 'use server'; which only runs on the server and thus has access to the database.
So the natural way is Server Component -> Client Component (use client) -> Server Action (use server). It's worth mentioning that server actions can be obviously used in Server Components too.

I also made a server action and I feel like this flow is better. Is the way to go just use server actions over server components? Maybe what I am trying to understand better is when to use server components over server actions over client components?
you are mixing up the terms my friend. Server actions are frequently used for data mutation, without creating an API endpoint. Performing data mutations on the server helps to ensure that operations are carried out securely, preventing unauthorized access or manipulation of data. You can read more about server actions and its benefits.
Server components are rendered on the server before being sent to the client. This can lead to faster initial page loads and improved time-to-interactive (TTI) performance, as the client receives pre-rendered content without the need for client-side rendering. Main power behind server actions and server components is servers typically have more computing resources (such as processing power, memory, and storage) compared to browsers. This allows servers to handle complex calculations and data manipulations more efficiently and faster.
Client components are used where you need user interactivity. think about it, if you have a button with onCLick prop, where can user click on the button, so this component should be a cient component. Also, if you use hooks in any component, this component should be a client component because hooks are technically tell browser when to re-render the component.
for the sharing data between components in your project depends on the size of your project. if you have a small size project, maybe you wont bother yourself setting up context api or redux. But if your application has complex state management requirements, you could implement context api or redux
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With