Creating a forum board with server-side rendering (SSR) . tsx way ;)

GuaSerius24jamGuaSerius24jam
3 min read

Set up Next.js with TypeScript

npx create-next-app forum-board --ts
cd forum-board

Server-Side Rendered (SSR) Pages

Create a page like pages/forum.tsx that fetches data server-side and renders HTML/CSS.

// pages/forum.tsx
import { GetServerSideProps } from 'next';
import { fetchCategories } from '../lib/api'; // Connect to your backend

interface ForumPageProps {
  categories: Category[];
}

export const getServerSideProps: GetServerSideProps<ForumPageProps> = async () => {
  const categories = await fetchCategories(); // Fetch from backend API
  return { props: { categories } };
};

const ForumPage: React.FC<ForumPageProps> = ({ categories }) => {
  return (
    <div className="forum-board">
      <h1>Forum Board (Works without JavaScript!)</h1>
      {categories.map((category) => (
        <div key={category.id} className="category">
          <h2>{category.name}</h2>
          <div className="thread-list">
            {category.threads.map((thread) => (
              <div key={thread.id} className="thread-item">
                <h3>{thread.title}</h3>
                <p>By {thread.author}</p>
              </div>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
};

export default ForumPage;

Backend API Integration (Example)

// lib/api.ts
export const fetchCategories = async (): Promise<Category[]> => {
  const response = await fetch('https://your-backend-api.com/categories');
  return response.json();
};

Add Forms with Zero-JS Fallback

Use traditional HTML forms with server-side processing for replies or new threads.

Create a Form (Works Without JavaScript)

// components/CreateThreadForm.tsx
const CreateThreadForm: React.FC = () => {
  return (
    <form method="POST" action="/api/create-thread">
      <input type="text" name="title" placeholder="Thread Title" required />
      <textarea name="content" placeholder="Content" required />
      <button type="submit">Create Thread</button>
    </form>
  );
};

Backend API Route (Next.js API Route)

// pages/api/create-thread.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { saveThreadToDB } from '../../lib/database';

export default async (req: NextApiRequest, res: NextApiResponse) => {
  if (req.method === 'POST') {
    const { title, content } = req.body;
    await saveThreadToDB({ title, content }); // Save to backend DB
    res.redirect(302, '/forum'); // Redirect after submission
  } else {
    res.status(405).end();
  }
};

Enhance with JavaScript (Redux/Context API)

For users with JavaScript enabled, add client-side interactivity.

Set Up Redux Toolkit

npm install @reduxjs/toolkit react-redux

Create a Redux Store

// lib/store.ts
import { configureStore } from '@reduxjs/toolkit';
import forumReducer from './forumSlice';

export const store = configureStore({
  reducer: {
    forum: forumReducer,
  },
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

Create a Slice for Forum Data

// lib/forumSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { Category } from '../types';

interface ForumState {
  categories: Category[];
}

const initialState: ForumState = {
  categories: [],
};

const forumSlice = createSlice({
  name: 'forum',
  initialState,
  reducers: {
    setCategories(state, action: PayloadAction<Category[]>) {
      state.categories = action.payload;
    },
  },
});

export const { setCategories } = forumSlice.actions;
export default forumSlice.reducer;

Hydrate the Store with SSR Data

// pages/_app.tsx
import { Provider } from 'react-redux';
import { store } from '../lib/store';

function MyApp({ Component, pageProps }) {
  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  );
}

export default MyApp;

Client-Side Interactivity

Add dynamic features (e.g., upvoting, live replies) using Redux and AJAX.

Example: Upvote a Thread (Client-Side)

// components/UpvoteButton.tsx
import { useDispatch } from 'react-redux';
import { upvoteThread } from '../lib/forumSlice';

const UpvoteButton: React.FC<{ threadId: string }> = ({ threadId }) => {
  const dispatch = useDispatch();

  const handleUpvote = async () => {
    await fetch('/api/upvote-thread', {
      method: 'POST',
      body: JSON.stringify({ threadId }),
    });
    dispatch(upvoteThread(threadId)); // Update Redux state
  };

  return <button onClick={handleUpvote}>Upvote</button>;
};

Styling

Use CSS to style server-rendered HTML. Example:

/* styles/globals.css */
.forum-board {
  padding: 20px;
}

.thread-item {
  border: 1px solid #ddd;
  padding: 10px;
  margin: 10px 0;
}

form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
  1. Zero-JS Users: See server-rendered HTML/CSS with basic form submissions.

  2. JS-Enabled Users: Get enhanced interactivity via Redux/Context API.

  3. Backend: Use a framework like Express, Django, or Firebase for API/database.

  4. Type Safety: Ensure all API calls and Redux actions are typed.

This approach balances accessibility for non-JS users with rich interactivity for others. For production, add error handling, authentication, and real-time updates (e.g., WebSockets).

0
Subscribe to my newsletter

Read articles from GuaSerius24jam directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

GuaSerius24jam
GuaSerius24jam

gua memang serious cakap lu, gua serious 24 jam. baik di jamban ,di meja makan atau bersenggama . serius...dohhh