Aamir Khan
Aamir Khan

Reputation: 11

[NextJS]: Passing list of organizations from a server to client component

Context: I have a server component that fetches a list of organizations and passes it on to a client component. The client component fills in the organizations state from the prop data. Later on, it does operations on it making changes to the data within. One example is changing the state of an organization from active to archived.

ServeComponent

export default async function ServerComponent({searchParams}) {
    const pageNumber = !!searchParams.page ? searchParams.page : 1;
    const organizations = await getOrganizations(session?.user.email, pageNumber);
 
 
    return <Organizations initialOrganizations={organizations}/>
}

ClientComponent

export default function Organizations({ initialOrganizations = [] }) {
  const [organizations, setOrganizations] = useState(initialOrganizations);
  const [selectedOrganization, setSelectedOrganization] = useState({});
  const [toggle, setToggle] = useState(true);
  const [tabs, setTabs] = useState([{ name: 'Active', current: true },
                                    { name: 'Archive', current: false }]);
  const [activeTab, setActiveTab] = useState('Active');
 
  const router = useRouter();
  const search = useSearchParams();

 
  useEffect(() => {
    const page = search.get('page');
    if(page) {
      router.push(`/portal/organizations?page=${page}`)
    
    }
  }, [search])

  const handleOrganizationUpdate = (updatedOrganization) => {
    setOrganizations((prevOrganizations) =>
      prevOrganizations.map((o) =>
        o.id === updatedOrganization.id ? updatedOrganization : o
      )
    );
  };

  const archiveOrganization = async (organizationId) => {
      const response =  await fetch('/api/organization/archive',{
          method: 'POST',
          headers: {
              "Content-Type": "application/json",
          },
          body: JSON.stringify({ organizationId })
      });
      if(response.ok) {
          const responseBody = await response.json();
          const updatedOrganization = responseBody.response;
          console.log(updatedOrganization)
          setOrganizations((prev) =>
          prev.map((organization) =>
            organization.id === updatedOrganization.id ? { ...organization, status: updatedOrganization.status } : organization
          )
        );
      }
  }

  return (
    toggle ?
    <>
      <Button variant='solid' href='/portal/organizations/create-organization'>
                <span>Create Organization</span>
      </Button>
      <Tab tabs={tabs} setTabs={setTabs} setActiveTab={setActiveTab}/>
      {organizations.map((organization) => (
        activeTab.toUpperCase() == organization.status &&
        <div
          key={organization.id}
          className="group flex justify-between mt-10 flex-row items-center hover:bg-slate-900 w-3/5 px-8 py-6 mb-5 border-b-cyan-50 rounded shadow-black hover:shadow-black shadow-md hover:shadow-lg"
        >
          <div className='flex flex-col'>
            <h2 className='text-xs text-slate-300'>Organization Name</h2>
            <h2 onClick={() => {setToggle(false); setSelectedOrganization(organization)}} className="text-base hover:underline">{organization.name}</h2>
          </div>
    
          <Button onClick={() => {archiveOrganization(organization.id)}}  className="opacity-0 transition-opacity duration-100 ease-in-out group-hover:opacity-100" variant="solid">
            {organization.status == "ACTIVE" ? <span>Archive</span> : <span>Active</span>}
          </Button>
        </div>
      ))}
    </>
    :
    <Organization organization={selectedOrganization} handleOrganizationUpdate={handleOrganizationUpdate} setToggle={setToggle}/>
  );
}

Problem: When the component is mounted and I do some operation, it shows the updated array. On remount it uses the stale data which was initially passed as props, which is obvious given that the props don't change and the state is re-initialized.

Please suggest a pattern which can solve this problem, which perhaps could be:

Upvotes: 1

Views: 186

Answers (1)

Aravind R
Aravind R

Reputation: 21

From what I understand, you want to fetch the latest data in the server component when some changes are made to the data. For that you can use cache: "no-store" to avoid caching behaviour of next js and show the updated data each time you visit the page. To revalidate a path after an data has changed, you can use the revalidatePath function.

Update 2024

From Next.js v15 onwards, the default behaviour of caching in fetch is cache: "no-store".

Upvotes: 1

Related Questions