1. npx create-react-app < name >
2. npm start
1. npm create vite@latest
2. # Enter project name
3. # Choose system vanilla, react, etc.
4. npm install
5. npm run dev
# or install in the current directory
npm create vite@latest . -- --template react
npm install sass
npm install react-bootstrap bootstrap
index.js
import "bootstrap/dist/css/bootstrap.min.css"
in App.js
import button from "react-bootstrap/Button"
<Button variant="primary">Filtern</Button>
import Container from "react-bootstrap/Container";
import Row from "react-bootstrap/Row";
import Col from "react-bootstrap/Col";
import Apod from "./components/Apod";
<Container>
<Row>
<Col>
<Food />
</Col>
</Row>
</Container>
npm install react-router-dom
App.jsx
import {BrowserRouter, Routes, Route} from "react-router-dom";
return (
<BrowserRouter>
<Routes>
<Route path="/products" element={<Products />} />
<Route path="/" element={<Main />} />
{/* Nested routes */}
<Route element={<Protected />}>
<Route path="/members" element={<Members />} />
</Route>
{/* Alternative with wrapper component */}
<Route
path="/members"
element={
<ProtectedRoute>
<Members />
</ProtectedRoute>
}
/>
<Route path="*" element={<PageNotFound />} />
</Routes>
</BrowserRouter>
)
Main.jsx
import { Link } from "react-router-dom";
return (
<>
<h1>Main</h1>
<Link to="/products">Products</Link>
</>
);
Protected.jsx
import { Navigate, Outlet } from "react-router-dom";
import { useAuth } from "./AuthProvider";
// For nested routes
const ProtectedRoute = () => {
const { user } = useAuth();
return user ? <Outlet /> : <Navigate to="/" />;
};
// or for Routes with wrapper component
const ProtectedRoute = ({ children }) => {
const { user } = useAuth();
return user ? children : <Navigate to="/" />;
};
export default ProtectedRoute;
import { useNavigate } from "react-router-dom";
navigate("/members", { state: { username: user.username } }); // Second parameter is optional
// members.jsx
import { useLocation } from "react-router-dom";
const location = useLocation(); // Returns the location object from the current URL
const username = location.state.username; // Get the values from the second parameter
import {useReducer} from "react";
function reducer(state, action){
switch (action.type){
case "increment":
return {count: state.count + 1}
case "decrement":
return {count: state.count - 1}
default:
return state
}
}
const [state, dispatch] = useReducer(reducer, {count: 0})
function increment(){
dispatch({type: "increment"})
}
function decrement(){
dispatch({type: "decrement"})
}
return (
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
)
Inside context/Products.js
import { useState, createContext, useContext } from "react";
import data from "../data";
export const ProductsContext = createContext();
function Products(props) {
const [products, setProducts] = useState(data);
const [productsInBasket, setProductsInBasket] = useState([]);
return <ProductsContext.Provider value={{ products, productsInBasket, setProductsInBasket }}>
{props.children}
</ProductsContext.Provider>;
}
export default Products;
// alternative export
export const useProducts = () => useContext(ProductsContext)
// consume alternative export
import {useProducts} from "../context/ProductsContext";
const {products, productsInBasket, setProductsInBasket} = useProducts();
Inside App.js
import Products from "./Products";
function App() {
return (
<Products>
<Router>...</Router>
</Products>
);
}
Inside Home.js
import { useContext } from "react";
import { ProductsContext } from "../context/Products";
function Home() {
const { products } = useContext(ProductsContext);
return <div>{products}</div>;
}
Folder structure
app/store.js;
features/dataSlice.js;
Inside app/store.js
import { configureStore } from "@reduxjs/toolkit";
import languageDataReducer from "../features/languageDataSlice";
export const store = configureStore({
reducer: {
languageData: languageDataReducer,
}, // Place for all the slices
});
Inside features/dataSlice.js
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
value: { fData: {}, selectedLanguage: "" },
};
export const languageDataSlice = createSlice({
name: "languageData",
initialState,
reducers: {
updateLanguageData: (state, action) => {
state.value.fData = action.payload;
state.value.selectedLanguage = action.payload.language;
},
},
});
export const { updateLanguageData } = languageDataSlice.actions;
export default languageDataSlice.reducer;
Inside a file where the store is read/updated
import { useSelector, useDispatch } from "react-redux";
import { updateLanguageData } from "../../features/languageDataSlice";
const languageData = useSelector((state) => state.languageData.value); // Get value from the state
const dispatch = useDispatch();
dispatch(updateLanguageData(value)); // Change the state
// In .env (VITE_ needs to be the prefix)
VITE_API_URL=http://localhost:3000
// Where VITE_API_URL is used
const API_URL = import.meta.env.VITE_API_URL;
For deployment a config.js could be used
export const API_URL = import.meta.env.VITE_API_URL || '';
On Render the environment variable needs to be set
Key: VITE_API_URL
Value: https://your-backend-service.onrender.com
// In .env (REACT_APP_ needs to be the prefix)
REACT_APP_API_URL=http://localhost:3000
// Where REACT_APP_API_URL is used
const API_URL = process.env.REACT_APP_API_URL;
.env
VITE_API_URL=http://localhost:3000
config.js
export const API_URL = import.meta.env.VITE_API_URL || "";
Where a frontend fetch is used
import { API_URL } from './config';
const BASE_URL = API_URL // needs to correspond with the backend url (e.g. http://localhost:3000)
await fetch(BASE_URL);
On the Render webpage the environment variable needs to be set
Key: VITE_API_URL
Value: https://your-backend-service.onrender.com
vite.config.js
server: {
port: 5173, // optional, default vite port
proxy: {
"/paypal": "http://localhost:3000"
}
}
// All routes pointing to /paypal will be redirected to the specified url
// No need to include cors for localhost