如何使用 Redux 将 Next.js 15 中的客户端选项卡组件转换为 SSR?

问题描述 投票:0回答:1

我的 Next.js 15 应用程序中有一个客户端选项卡组件,我想将其转换为使用服务器端渲染 (SSR)。

有人可以指导我如何更新或修改代码以实现该组件的 SSR 吗?以下是我当前的代码。

此外,我在我的应用程序中使用 Redux。是否可以在 Next.js 中将 Redux 与 SSR 结合使用?如果是,您能否提供一些关于如何针对我的用例实施它的指导或示例?

enter image description here

"use client"
import React, { useState } from 'react';
import SectionTitle from '../ui/SectionTitle';
import SectionSubTitle from '../ui/SectionSubTitle';
import Button from '../ui/Button';
import usePricing from '@/lib/store/hooks/usePricing';


const Pricing = () => {
  const [activeTab, setActiveTab] = useState('INDIVIDUAL');

  const tabs = ['INDIVIDUAL', 'STUDENT', 'ORGANIZATION'];

  const plansData = {
    INDIVIDUAL: [
      {
        title: 'Basic',
        price: '$9.99/month',
        features: [
          'Access to 100 tutorial videos per month',
          'Basic sewing and pattern-making toolkits',
          'Standard support (email only)',
          'Downloadable templates for beginners'
        ],
        buttonStyle: 'outline'
      },
      {
        title: 'Pro',
        price: '$19.99/month',
        features: [
          'Unlimited access to all tutorial videos',
          'Intermediate sewing and pattern-making toolkits',
          'Access to exclusive video content and webinars',
          'Priority support (email and live chat)',
          'Monthly downloadable patterns for intermediate levels',
          'Community forum access for tips and advice'
        ],
        buttonStyle: 'filled'
      },
      {
        title: 'Premium',
        price: '$29.99/month',
        features: [
          'All previous features',
          'Advanced sewing toolkits & pattern-making courses',
          'Personalized video consultations\n(1 session per month)',
          'Early access to new tutorials and pattern designs',
          'Exclusive discounts on partner fabric and sewing tool shops',
          'Custom pattern requests (one per month)'
        ],
        buttonStyle: 'outline'
      }
    ],
    STUDENT: [
      {
        title: 'Student Basic',
        price: '$4.99/month',
        features: [
          'Access to 50 tutorial videos per month',
          'Basic sewing toolkits',
          'Email support',
          'Student community access'
        ],
        buttonStyle: 'outline'
      },
      {
        title: 'Student Pro',
        price: '$9.99/month',
        features: [
          'Unlimited access to all tutorial videos',
          'Intermediate sewing toolkits',
          'Priority email support',
          'Access to student webinars'
        ],
        buttonStyle: 'filled'
      }
    ],
    ORGANIZATION: [
      {
        title: 'Org Basic',
        price: '$49.99/month',
        features: [
          'Access for up to 10 members',
          'Basic sewing toolkits',
          'Email support',
          'Organization dashboard'
        ],
        buttonStyle: 'outline'
      },
      {
        title: 'Org Pro',
        price: '$99.99/month',
        features: [
          'Access for up to 50 members',
          'Advanced sewing toolkits',
          'Priority support',
          'Custom organization webinars'
        ],
        buttonStyle: 'filled'
      }
    ]
  };

  return (
    <section className=" max-w-8xl mx-auto w-full pb-10 lg:pb-20 pt-[170px] px-4 lg:px-12.5 border-b border-bw-3 pricing" id='pricing'>
      <div className='flex flex-col items-center gap-4 pb-10'>
        <SectionTitle className='!text-3.5xl' title="Pricing" />
        <SectionSubTitle subtitle="Unlock exclusive features with our tailored plans" />
      </div>

      <div className=" flex justify-center gap-4 mx-auto bg-secondary-1 w-max p-1 rounded-[15px] mb-3 lg:mb-[74px]">
        {tabs.map(tab => (
          <button
            key={tab}
            className={`tab px-3 lg:px-5 py-3 lg:py-2.5 cursor-pointer font-inter font-normal text-xs leading-[18px]  rounded-lg.5

             ${activeTab === tab ? 'active bg-primary-10 text-white rounded-lg' : 'bg-secondary-1 text-black'}`}
            onClick={() => setActiveTab(tab)}
          >
            {tab}
          </button>
        ))}
      </div>

      <div className="flex items-center gap-[30px] justify-center flex-col lg:flex-row">
        {plansData[activeTab].map((plan, index) => (
          <div
            key={index}
            className={`max-w-full lg:max-w-[480px] w-full min-h-[401px] lg:min-h-[580px] gap-4 p-4 lg:p-6 rounded-2xl lg:rounded-lg.5 border border-gray-200 flex flex-col transition-all duration-300 ${plan.title.toLowerCase()} ${plan.title.toLowerCase() == 'pro' ? 'border-[3px] border-primary-5 transform scale-y-105' : ''}`}
          >
            <h3 className='text-center text-2xl md:text-2.5xl text-secondary-8 font-unbounded font-semibold leading-7 md:leading-8  mb-8 relative
            after:content-[""] after:absolute after:-bottom-[10px] after:left-0 after:right-0 after:mx-auto after:w-[60px] after:h-px after:bg-gray-200'>{plan.title}</h3>
            <div className="pricing-features flex-1 text-left">
              <h4 className='font-unbounded font-normal text-base lg:text-lg leading-[18px] lg:leading-5 text-secondary-8 text-center mb-3'>Features:</h4>
              <ul className='m-0 p-0 flex flex-col gap-[6px] lg:gap-2'>
                {plan.features.map((feature, i) => (
                  <li key={i} className='flex gap-2 items-center list-none font-inter font-normal text-base leading-6 text-secondary-5'>
                    <span className="bg-primary-5 min-w-[5px] min-h-[5px] max-w-[5px] max-h-[5px] rounded-full"></span>
                    {feature}
                  </li>
                ))}
              </ul>
            </div>
            <div className='flex flex-col items-center gap-5 justify-center'>
              <div className="font-unbounded  font-semibold text-base md:text-lg  leading-5 text-primary-10 tracking-[-0.5px]">{plan.price}</div>

            <Button
              variant={plan.title.toLowerCase() == 'pro' ? 'Primary' : 'Secondary'}
                size="Medium"
                className="w-full md:!w-fit"
              iconPosition="right" >
              GET PLAN
            </Button>
            </div>
          </div>
        ))}
      </div>
    </section>
  );
};
export default Pricing;
next.js redux server-side-rendering
1个回答
0
投票

从客户端组件转换为服务器组件的步骤

  1. 从顶部删除“使用客户端”

  2. 使用“useServerState”而不是“use client”钩子

// Example code to use useServerState hook 
import { useServerState } from 'next/server';

export default function MyServerComponent() {
    const [count, setCount] = useServerState(0);

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(count + 1)}>Increment</button>
        </div>
    );
}

将 redux 与 nextjs + SSR 结合使用

缺点

disadvantage of usibg state managment system of server side

来源:- https://medium.com/@mak-dev/zustand-with-next-js-14-server-components-da9c191b73df

解决方案

将服务器端组件嵌套在客户端组件中,或将组件端代码嵌套在服务器组件中,并且仅在客户端内部使用状态redux 在客户端组件中使用服务器组件的快速视频

使用 useserverState 钩子(如上所示)而不是对服务器端组件使用 redux 钩子

© www.soinside.com 2019 - 2024. All rights reserved.