Behind the product: Replit | Amjad Masad (co-founder and CEO)
Explore how Replit's AI-powered platform is transforming coding, making it accessible for everyone, and reshaping the future of product development.
Discover the truth behind the SQL in React drama and learn secure patterns for modern web development.
Theo - t3․ggJune 17, 2024This article was AI-generated based on this episode
The SQL in React drama kicked off with an initial tweet by Adam Rackus. At NextConf, Sam Selikoff showcased a compelling pattern in his presentation.
Selikoff demonstrated using a button with a form action that inserts a value into bookmarks. While this was intended to showcase composable patterns, it led to widespread outrage.
The community's reaction was notably intense. Concerns immediately arose about potential SQL injections and the mixing of server-side code in client code. The primary misconception was the assumption that SQL queries were being controlled by the client, leading to security vulnerabilities. In reality, the server-side execution of the queries ensures their safety.
'Use server' ensures server-side execution:
use server
directive binds server-side actions to client-side interactions.Sanitizing SQL queries with template tag functions:
Security measures in place:
The use server
directive in Next.js creates backend endpoints that the frontend can hit. It ensures actions tied to client-side interactions execute on the server.
Here's a simple example:
import { useServer } from 'next/server';
async function deletePostAction(postId) {
useServer();
console.log(`Deleting post with ID: ${postId}`);
// Perform your server-side logic here.
}
// Usage in a component
function Post({ post }) {
return (
<form action={deletePostAction.bind(null, post.id)}>
<button type="submit">Delete Post</button>
</form>
);
}
When the button is clicked, use server
triggers, binding the action to the server. The form posts the data to the server-side function, executing securely away from client vulnerabilities.
This method keeps SQL code off the client while maintaining secure server actions in React. Implementing use server
ensures robust security and maintains separation of concerns.
Separating concerns is crucial in modern web development. It ensures code clarity, maintainability, and security. Here are the best practices to achieve it:
Utilize ORMs:
Implement Data Access Layers:
Leverage Server Actions:
use server
in Next.js binds client-side actions securely to backend logic.Flexible Architecture:
Adopting these practices ensures secure and efficient web development, aligning with secure web development patterns and enhancing the maintainability of your application.
Creating a data access layer (DAL) in React ensures secure and efficient data handling. Here's a step-by-step guide:
Set up a new file for the data layer:
// src/dataLayer/index.js
import { serverOnly } from 'your-server-only-package';
import { db } from 'your-database-setup';
serverOnly();
export const dataLayer = {
queries: {
getPosts: async () => {
return await db.query.posts.findMany();
},
},
mutations: {
deletePost: async (postId) => {
return await db.delete.posts.where({ id: postId });
},
},
};
Use the data layer in your component:
// src/components/PostList.js
import { dataLayer } from '../dataLayer';
function PostList() {
const posts = await dataLayer.queries.getPosts();
const handleDelete = async (postId) => {
await dataLayer.mutations.deletePost(postId);
// Refresh posts or update state
};
return (
<div>
{posts.map((post) => (
<div key={post.id}>
<p>{post.name}</p>
<button onClick={() => handleDelete(post.id)}>Delete</button>
</div
tRPC is a powerful tool for managing server actions in React. It helps in validating inputs and ensures your server-side logic is robust and secure.
Here's how tRPC can be integrated with server actions:
First, define a server action procedure using tRPC:
import { initTRPC } from '@trpc/server';
const t = initTRPC();
export const createPost = t.procedure
.input({
title: 'string',
})
.mutation(async ({ input }) => {
// Logic to create a post
console.log(`Creating post with title: ${input.title}`);
return { success: true };
});
Next, bind this procedure to a form in your React component:
function CreatePostForm() {
const createPostAction = trpc.createPost.useMutation();
const handleSubmit = (event) => {
event.preventDefault();
const title = event.target.elements.title.value;
createPostAction.mutate({ title });
};
return (
<form onSubmit={handleSubmit}>
<input name="title" type="text" required />
<button type="submit">Create Post</button>
</form>
);
}
Benefits of using tRPC with server actions:
Modeling data in React can be approached in various ways. Here are three recommended patterns:
Direct SQL in Components:
Pros:
Cons:
HTTP APIs:
Pros:
Cons:
Data Access Layers:
Pros:
Cons:
Choose the pattern that best fits your project's needs. Each approach offers its own set of benefits and challenges to consider.
Explore how Replit's AI-powered platform is transforming coding, making it accessible for everyone, and reshaping the future of product development.
Explore why modern server-side JavaScript isn't just PHP all over again, but a leap forward in web development.
Discover the journey of creating a lightning-fast JavaScript SSR framework and the surprising techniques that led to a 5x speed improvement.