Components and Props
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
const element = <Welcome name="John" />;
State and Lifecycle
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
return () => {
};
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
function NameForm() {
const [name, setName] = useState('');
return (
<input
value={name}
onChange={e => setName(e.target.value)}
/>
);
}
function DataFetcher() {
const [data, setData] = useState(null);
useEffect(() => {
fetchData().then(setData);
}, []);
return data ? <div>{data}</div> : <div>Loading...</div>;
}
const ThemeContext = React.createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button className={theme}>Themed Button</button>;
}
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
);
}
Event Handling
function ActionButton() {
const handleClick = (e) => {
e.preventDefault();
console.log('Button clicked');
};
return (
<button onClick={handleClick}>
Click me
</button>
);
}
const ThemeContext = React.createContext({
theme: 'light',
toggleTheme: () => {}
});
function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
const toggleTheme = () => {
setTheme(theme === 'light' ? 'dark' : 'light');
};
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
{children}
</ThemeContext.Provider>
);
}
function ThemedComponent() {
const { theme, toggleTheme } = useContext(ThemeContext);
return (
<div className={theme}>
<button onClick={toggleTheme}>Toggle Theme</button>
</div>
);
}
function useForm(initialValues) {
const [values, setValues] = useState(initialValues);
const handleChange = (e) => {
const { name, value } = e.target;
setValues(prev => ({
...prev,
[name]: value
}));
};
const resetForm = () => {
setValues(initialValues);
};
return [values, handleChange, resetForm];
}
function SignupForm() {
const [values, handleChange, resetForm] = useForm({
username: '',
email: '',
password: ''
});
const handleSubmit = (e) => {
e.preventDefault();
console.log(values);
resetForm();
};
return (
<form onSubmit={handleSubmit}>
<input
name="username"
value={values.username}
onChange={handleChange}
/>
{}
</form>
);
}
function withSubscription(WrappedComponent, selectData) {
return function(props) {
const [data, setData] = useState(null);
useEffect(() => {
const subscription = DataSource.subscribe(data => {
setData(selectData(data, props));
});
return () => subscription.unsubscribe();
}, [props]);
return <WrappedComponent data={data} {...props} />;
};
}
const CommentListWithSubscription = withSubscription(
CommentList,
(DataSource, props) => DataSource.getComments()
);
class Mouse extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
};
render() {
return (
<div onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
<Mouse render={({ x, y }) => (
<h1>Mouse position: {x}, {y}</h1>
)}/>
const MemoizedComponent = React.memo(function MyComponent(props) {
return (
<div>{props.name}</div>
);
});
useMemo and useCallback
function ExpensiveComponent({ data, onItemSelect }) {
const processedData = useMemo(() => {
return expensiveOperation(data);
}, [data]);
const handleSelect = useCallback((item) => {
onItemSelect(item.id);
}, [onItemSelect]);
return (
<div>
{processedData.map(item => (
<Item
key={item.id}
item={item}
onSelect={handleSelect}
/>
))}
</div>
);
}
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
);
}
const increment = () => ({
type: 'INCREMENT'
});
function counterReducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
default:
return state;
}
}
function Counter({ count, increment }) {
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}
export default connect(
state => ({ count: state }),
{ increment }
)(Counter);
Zustand Example
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 } = useStore();
return (
<button onClick={increment}>
Count: {count}
</button>
);
}
import { render, fireEvent } from '@testing-library/react';
test('increments counter', () => {
const { getByText } = render(<Counter />);
const button = getByText(/increment/i);
fireEvent.click(button);
expect(getByText(/count: 1/i)).toBeInTheDocument();
});
import { renderHook, act } from '@testing-library/react-hooks';
test('useCounter', () => {
const { result } = renderHook(() => useCounter());
act(() => {
result.current.increment();
});
expect(result.current.count).toBe(1);
});
Error Handling
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/users/:id" element={<UserProfile />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}