Ecosystem
React ecosystem including popular libraries, tools, build systems, and development workflow for modern React applications.
UI Component Libraries
Material-UI (MUI)
npm install @mui/material @emotion/react @emotion/styled
import { Button, TextField, Box, Typography } from '@mui/material';
import { ThemeProvider, createTheme } from '@mui/material/styles';
const theme = createTheme({
palette: {
primary: {
main: '#1976d2',
},
},
});
function App() {
return (
<ThemeProvider theme={theme}>
<Box sx={{ p: 2 }}>
<Typography variant="h4" gutterBottom>
My App
</Typography>
<TextField label="Email" variant="outlined" fullWidth margin="normal" />
<Button variant="contained" color="primary">
Submit
</Button>
</Box>
</ThemeProvider>
);
}
Ant Design
npm install antd
import { Button, Form, Input, Card, Space } from 'antd';
import 'antd/dist/antd.css';
function App() {
const onFinish = values => {
console.log('Form values:', values);
};
return (
<Card title="Login Form" style={{ maxWidth: 400, margin: '50px auto' }}>
<Form onFinish={onFinish} layout="vertical">
<Form.Item
label="Email"
name="email"
rules={[{ required: true, type: 'email' }]}
>
<Input />
</Form.Item>
<Form.Item
label="Password"
name="password"
rules={[{ required: true }]}
>
<Input.Password />
</Form.Item>
<Form.Item>
<Space>
<Button type="primary" htmlType="submit">
Login
</Button>
<Button>Cancel</Button>
</Space>
</Form.Item>
</Form>
</Card>
);
}
Chakra UI
npm install @chakra-ui/react @emotion/react @emotion/styled framer-motion
import {
ChakraProvider,
Box,
Button,
Input,
VStack,
Heading,
} from '@chakra-ui/react';
function App() {
return (
<ChakraProvider>
<Box p={8}>
<VStack spacing={4} align="stretch">
<Heading>Welcome</Heading>
<Input placeholder="Enter your email" />
<Button colorScheme="blue" size="lg">
Get Started
</Button>
</VStack>
</Box>
</ChakraProvider>
);
}
Styling Solutions
Styled Components
npm install styled-components
import styled from 'styled-components';
const Button = styled.button`
background: ${props => (props.primary ? '#007bff' : '#6c757d')};
color: white;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
&:hover {
background: ${props => (props.primary ? '#0056b3' : '#545b62')};
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
`;
const Container = styled.div`
max-width: 1200px;
margin: 0 auto;
padding: 20px;
`;
function App() {
return (
<Container>
<Button primary>Primary Button</Button>
<Button>Secondary Button</Button>
</Container>
);
}
Emotion
npm install @emotion/react @emotion/styled
import { css } from '@emotion/react';
import styled from '@emotion/styled';
const buttonStyle = css`
background: #007bff;
color: white;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
&:hover {
background: #0056b3;
}
`;
const StyledButton = styled.button`
${buttonStyle}
font-size: ${props => (props.size === 'large' ? '18px' : '14px')};
`;
function App() {
return (
<div>
<button css={buttonStyle}>CSS Prop</button>
<StyledButton size="large">Styled Component</StyledButton>
</div>
);
}
Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
function App() {
return (
<div className="min-h-screen bg-gray-100">
<header className="bg-white shadow">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 className="text-3xl font-bold text-gray-900 py-6">My App</h1>
</div>
</header>
<main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
<div className="px-4 py-6 sm:px-0">
<div className="border-4 border-dashed border-gray-200 rounded-lg p-8">
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Click me
</button>
</div>
</div>
</main>
</div>
);
}
Data Fetching Libraries
React Query (TanStack Query)
npm install @tanstack/react-query
import {
QueryClient,
QueryClientProvider,
useQuery,
} from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<UserList />
</QueryClientProvider>
);
}
function UserList() {
const {
data: users,
isLoading,
error,
} = useQuery({
queryKey: ['users'],
queryFn: async () => {
const response = await fetch('/api/users');
return response.json();
},
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
SWR
npm install swr
import useSWR from 'swr';
const fetcher = url => fetch(url).then(res => res.json());
function UserProfile({ userId }) {
const {
data: user,
error,
isLoading,
} = useSWR(`/api/users/${userId}`, fetcher);
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error loading user</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
Apollo Client (GraphQL)
npm install @apollo/client graphql
import {
ApolloClient,
InMemoryCache,
ApolloProvider,
gql,
useQuery,
} from '@apollo/client';
const client = new ApolloClient({
uri: 'https://api.example.com/graphql',
cache: new InMemoryCache(),
});
const GET_USERS = gql`
query GetUsers {
users {
id
name
email
}
}
`;
function App() {
return (
<ApolloProvider client={client}>
<UserList />
</ApolloProvider>
);
}
function UserList() {
const { loading, error, data } = useQuery(GET_USERS);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{data.users.map(user => (
<li key={user.id}>
{user.name} - {user.email}
</li>
))}
</ul>
);
}
Form Libraries
Formik
npm install formik yup
import { Formik, Form, Field, ErrorMessage } from 'formik';
import * as Yup from 'yup';
const validationSchema = Yup.object({
email: Yup.string().email('Invalid email').required('Required'),
password: Yup.string().min(6, 'Too short').required('Required'),
});
function LoginForm() {
return (
<Formik
initialValues={{ email: '', password: '' }}
validationSchema={validationSchema}
onSubmit={(values, { setSubmitting }) => {
setTimeout(() => {
console.log(values);
setSubmitting(false);
}, 400);
}}
>
{({ isSubmitting }) => (
<Form>
<Field type="email" name="email" placeholder="Email" />
<ErrorMessage name="email" component="div" />
<Field type="password" name="password" placeholder="Password" />
<ErrorMessage name="password" component="div" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
</Form>
)}
</Formik>
);
}
React Hook Form
npm install react-hook-form @hookform/resolvers yup
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import * as yup from 'yup';
const schema = yup.object({
email: yup.string().email().required(),
password: yup.string().min(6).required(),
});
function LoginForm() {
const {
register,
handleSubmit,
formState: { errors },
} = useForm({
resolver: yupResolver(schema),
});
const onSubmit = data => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} type="email" placeholder="Email" />
{errors.email && <p>{errors.email.message}</p>}
<input {...register('password')} type="password" placeholder="Password" />
{errors.password && <p>{errors.password.message}</p>}
<button type="submit">Submit</button>
</form>
);
}
Animation Libraries
Framer Motion
npm install framer-motion
import { motion, AnimatePresence } from 'framer-motion';
import { useState } from 'react';
function AnimatedComponent() {
const [isVisible, setIsVisible] = useState(false);
return (
<div>
<button onClick={() => setIsVisible(!isVisible)}>Toggle</button>
<AnimatePresence>
{isVisible && (
<motion.div
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.3 }}
>
<h2>Animated Content</h2>
</motion.div>
)}
</AnimatePresence>
<motion.button whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }}>
Hover me
</motion.button>
</div>
);
}
React Spring
npm install @react-spring/web
import { useSpring, animated } from '@react-spring/web';
import { useState } from 'react';
function SpringAnimation() {
const [flip, setFlip] = useState(false);
const props = useSpring({
to: { opacity: flip ? 1 : 0 },
from: { opacity: 0 },
reset: true,
reverse: flip,
delay: 200,
config: { duration: 1000 },
});
return (
<div>
<animated.div style={props}>I will fade in and out</animated.div>
<button onClick={() => setFlip(!flip)}>Click me</button>
</div>
);
}
Development Tools
Storybook
npx storybook@latest init
// Button.stories.js
import { Button } from './Button';
export default {
title: 'Example/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
backgroundColor: { control: 'color' },
},
};
export const Primary = {
args: {
primary: true,
label: 'Button',
},
};
export const Secondary = {
args: {
label: 'Button',
},
};
export const Large = {
args: {
size: 'large',
label: 'Button',
},
};
React DevTools
# Install browser extension
# Chrome: React Developer Tools
# Firefox: React Developer Tools
ESLint and Prettier
npm install -D eslint prettier eslint-config-prettier eslint-plugin-prettier
// .eslintrc.js
{
"extends": ["react-app", "react-app/jest", "prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error"
}
}
Build Tools
Vite
npm create vite@latest my-react-app -- --template react
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 3000,
open: true,
},
build: {
outDir: 'dist',
sourcemap: true,
},
});
Webpack (Custom Setup)
npm install -D webpack webpack-cli webpack-dev-server
npm install -D @babel/core @babel/preset-env @babel/preset-react babel-loader
npm install -D html-webpack-plugin css-loader style-loader
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react'],
},
},
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
}),
],
devServer: {
port: 3000,
open: true,
},
};
Testing Tools
Jest and React Testing Library
npm install -D @testing-library/react @testing-library/jest-dom @testing-library/user-event
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
};
Cypress
npm install -D cypress
// cypress/e2e/app.cy.js
describe('App E2E', () => {
it('renders welcome message', () => {
cy.visit('/');
cy.contains('Welcome to React');
});
it('can navigate to about page', () => {
cy.visit('/');
cy.get('[data-testid=about-link]').click();
cy.url().should('include', '/about');
});
});
State Management
Redux Toolkit
npm install @reduxjs/toolkit react-redux
import { configureStore, createSlice } from '@reduxjs/toolkit';
import { Provider, useSelector, useDispatch } from 'react-redux';
// Slice
const counterSlice = createSlice({
name: 'counter',
initialState: { value: 0 },
reducers: {
increment: state => {
state.value += 1;
},
decrement: state => {
state.value -= 1;
},
},
});
// Store
const store = configureStore({
reducer: {
counter: counterSlice.reducer,
},
});
// Component
function Counter() {
const count = useSelector(state => state.counter.value);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(counterSlice.actions.increment())}>
+
</button>
<button onClick={() => dispatch(counterSlice.actions.decrement())}>
-
</button>
</div>
);
}
// App
function App() {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
Zustand
npm install zustand
import { create } from 'zustand';
const useStore = create(set => ({
count: 0,
increment: () => set(state => ({ count: state.count + 1 })),
decrement: () => set(state => ({ count: state.count - 1 })),
}));
function Counter() {
const { count, increment, decrement } = useStore();
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
);
}
Utility Libraries
Lodash
npm install lodash
import { debounce, groupBy, sortBy } from 'lodash';
import { useState, useCallback } from 'react';
function UserList({ users }) {
const [searchTerm, setSearchTerm] = useState('');
const debouncedSearch = useCallback(
debounce(term => {
// Perform search
console.log('Searching for:', term);
}, 300),
[]
);
const handleSearch = e => {
const term = e.target.value;
setSearchTerm(term);
debouncedSearch(term);
};
const groupedUsers = groupBy(users, 'department');
const sortedUsers = sortBy(users, 'name');
return (
<div>
<input
type="text"
value={searchTerm}
onChange={handleSearch}
placeholder="Search users..."
/>
{/* Render users */}
</div>
);
}
Date-fns
npm install date-fns
import { format, formatDistanceToNow, isToday } from 'date-fns';
function PostDate({ createdAt }) {
const date = new Date(createdAt);
return (
<div>
<time dateTime={createdAt}>
{isToday(date)
? `Today at ${format(date, 'h:mm a')}`
: formatDistanceToNow(date, { addSuffix: true })}
</time>
</div>
);
}
Performance Tools
React Virtualized
npm install react-window react-window-infinite-loader
import { FixedSizeList as List } from 'react-window';
function VirtualizedList({ items }) {
const Row = ({ index, style }) => (
<div style={style}>{items[index].name}</div>
);
return (
<List height={600} itemCount={items.length} itemSize={50} width="100%">
{Row}
</List>
);
}
React.memo and useMemo
import { memo, useMemo } from 'react';
const ExpensiveComponent = memo(function ExpensiveComponent({ data }) {
const processedData = useMemo(() => {
return data.map(item => ({
...item,
processed: true,
}));
}, [data]);
return (
<div>
{processedData.map(item => (
<div key={item.id}>{item.name}</div>
))}
</div>
);
});
Quick Reference
Popular Libraries by Category
UI Components:
- Material-UI (MUI)
- Ant Design
- Chakra UI
- React Bootstrap
Styling:
- Styled Components
- Emotion
- Tailwind CSS
- CSS Modules
State Management:
- Redux Toolkit
- Zustand
- Jotai
- Recoil
Data Fetching:
- React Query (TanStack Query)
- SWR
- Apollo Client
- Relay
Forms:
- React Hook Form
- Formik
- Final Form
Animation:
- Framer Motion
- React Spring
- React Transition Group
Development Tools:
- Storybook
- React DevTools
- ESLint + Prettier
- TypeScript
Installation Commands
# UI Library
npm install @mui/material @emotion/react @emotion/styled
# State Management
npm install @reduxjs/toolkit react-redux
# Data Fetching
npm install @tanstack/react-query
# Forms
npm install react-hook-form
# Animation
npm install framer-motion
# Development
npm install -D @storybook/react