====== React ====== ===== References ===== * [[https://github.com/typescript-cheatsheets/react-typescript-cheatsheet|React-Typescript cheatsheet]] ===== Starter commands ===== yarn create react-app projectName --template typescript yarn add node-sass react-router-dom @types/react-router-dom @types/react-dom ===== .htaccess ===== RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] ===== Environments ===== Development / production environments can be set as following interface Env { ENV_STATUS: string; API_HOST: string; } const development: Env = { ENV_STATUS: "development", API_HOST: "localhost:3333" }; const production: Env = { ENV_STATUS: "production", API_HOST: "https://server.paperkeeper.org:3333" }; const config = process.env.REACT_APP_ENV === "development" ? development : production; export const Environment = { ...config }; To pass the the env variable modify ''package.json'' to ... "start": "REACT_APP_ENV=production react-scripts start", "start:dev": "REACT_APP_ENV=development react-scripts start", "build": "REACT_APP_ENV=production react-scripts build", ... ===== Snippets ===== ==== Component props ==== import React from 'react'; type CardProps = { title: string, paragraph: string parentFunc: (s: string) => void; } export const Card = ({ title, paragraph }: CardProps) =>

{ title }

{ paragraph }

const el = parentFunc(title)} />
====Redux ==== Redux store implementation which appeals to me these days. import { createStore, compose } from 'redux'; import { rootReducer } from './reducers'; declare global { interface Window { __REDUX_DEVTOOLS_EXTENSION__?: Function; __REDUX_DEVTOOLS_EXTENSION_COMPOSE__?: typeof compose; } } export interface StoreState { bill: number; percentage: number; split: number; } export const store = createStore( rootReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__(), ); import { Action } from 'redux'; export enum ActionTypes { BillChange = '[Bill] change', PercentageChange = '[Percentage] change', SplitIncrement = '[Split] increment', SplitDecrement = '[Split] decrement', Reset = '[Reset]', } export interface BillChangeAction extends Action { type: ActionTypes.BillChange; payload: string; } export interface PercentageChangeAction extends Action { type: ActionTypes.PercentageChange; payload: string; } export interface SplitIncrementAction extends Action { type: ActionTypes.SplitIncrement; } export interface SplitDecrementAction extends Action { type: ActionTypes.SplitDecrement; } export interface ResetAction extends Action { type: ActionTypes.Reset; } export type Actions = | BillChangeAction | PercentageChangeAction | SplitIncrementAction | SplitDecrementAction | ResetAction; import { Reducer } from 'redux'; import { StoreState } from '.'; import { Actions, ActionTypes } from './actions'; export const initalState: StoreState = { bill: 0, percentage: 0, split: 1, }; export const rootReducer: Reducer = ( state = initalState, action, ) => { switch (action.type) { case ActionTypes.BillChange: return { ...state, bill: Number(action.payload), }; case ActionTypes.PercentageChange: return { ...state, percentage: Number(action.payload), }; case ActionTypes.SplitIncrement: return { ...state, split: state.split + 1, }; case ActionTypes.SplitDecrement: const split = state.split - 1; return { ...state, split: split >= 1 ? split : state.split, }; case ActionTypes.Reset: return initalState; default: return state; } }; import { StoreState } from '.'; export type StoreSelector = (state: StoreState) => T; export const selectBill: StoreSelector = state => state.bill; export const selectPercentage: StoreSelector = state => state.percentage; export const selectSplit: StoreSelector = state => state.split; export const selectTotal: StoreSelector = state => { const total = state.bill + state.bill * (state.percentage / 100); return total.toFixed(2); }; export const selectTip: StoreSelector = state => { const tip = state.bill * (state.percentage / 100); return tip.toFixed(2); }; export const selectPerPerson: StoreSelector = state => { const perPerson = (state.bill + state.bill * (state.percentage / 100)) / state.split; return perPerson.toFixed(2); }; import * as React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { selectBill, selectSplit, selectPercentage } from '../store/selectors'; import { ActionTypes } from '../store/actions'; export const MyComponent = () => { const split = useSelector(selectSplit); const dispatch = useDispatch(); return (
{split}
) }
===== Useful libraries ===== * [[https://react-icons.netlify.com|react-icons]] * [[https://reacttraining.com/react-router/web/guides/quick-start|react-router-dom]] * [[https://www.npmjs.com/package/react-masonry-css|react-mansory-css]] * [[https://www.npmjs.com/package/uuid|uuid]] * [[https://react-hook-form.com/|react-hook-form]]