Client
Server
Database
HTTP
browser
request
html page
Client
Server
Database
HTTP
React in browser, mobile app...
API
request
data
Single page application
Web server
html, js
npx create-react-app my-app --template typescript
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Dependency management
{
"name": "my-package",
"version": "1.0.0",
"description": "This is just description of my awesome package",
"main": "index.js",
"scripts": {
"dev": "nodemon --exec npm run start",
"start": "tsc && node dist/index.js",
"test": "mocha --opts mocha.opts"
},
"author": "Martin Nuc",
"license": "ISC",
"dependencies": {
"@types/chai": "4.0.4",
"@types/mocha": "2.2.43",
"@types/node": "8.0.28",
"@types/sinon": "2.3.4",
"chai": "4.1.2",
"mocha": "3.5.3",
"nodemon": "1.12.1",
"sinon": "3.2.1",
"ts-node": "3.3.0",
"typescript": "2.5.2"
}
}
package.json
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Shortcut for start and test scripts only. For others you have to use npm run
Runs any script from npm.
👉
npm install lodash
installs lodash library:
npm install -D @types/lodash
installs lodash type definitions:
import lodash from 'lodash';
lodash.difference([1, 2, 3], [2, 3]);
{
"name": "my-package",
"version": "1.0.0",
"description": "This is just description of my awesome package",
"main": "index.js",
"scripts": {
"dev": "nodemon --exec npm run start",
"start": "tsc && node dist/index.js",
"test": "mocha --opts mocha.opts"
},
"author": "Martin Nuc",
"license": "ISC",
"dependencies": {
"@types/chai": "4.0.4",
"@types/mocha": "2.2.43",
"@types/node": "8.0.28",
"@types/sinon": "2.3.4",
"lodash": "4.17.5",
"chai": "4.1.2",
"mocha": "3.5.3",
"nodemon": "1.12.1",
"sinon": "3.2.1",
"ts-node": "3.3.0",
"typescript": "2.5.2"
}
}
package.json
6.11.2
patch
minor version
major version
6.11.2
patch
minor version
major version
- major changes, breaks API
6.11.2
patch
minor version
- new features
- doesn't break API
major version
- major changes, breaks API
6.11.2
patch
- only bugfixes
minor version
- new features
- doesn't break API
major version
- major changes, breaks API
const label = React.createElement('a', {
href: 'https://google.com'
}, 'Go to Google.com');
<a href="https://google.com">Go to Google.com</a>
children
props
type
import React from 'react';
function App() {
return (
<div className="App">
Hello
</div>
);
}
function App() {
return React.createElement('div', { className: 'App' }, 'Hello');
}
import React from 'react';
function App() {
return (
<div className="App">
Hello
</div>
);
}
function App() {
return React.createElement('div', { className: 'App'}, 'Hello');
}
import React from 'react';
function App() {
return (
<div>
Yes
</div>
<div>
No
</div>
);
}
function App() {
return ????????
}
import React from 'react';
function App() {
return (
<>
<div>
Yes
</div>
<div>
No
</div>
</>
);
}
function App() {
return <h1>Hello</h1>;
}
function App() {
let something = 'hello';
return <div>{something}</div>;
}
function Array() {
let array = [1,2,3];
return <div>
{array.map((item, index) => <span key={index}>{item}</span>)}
</div>;
}
type Props = {
name: string;
};
function NameComponent(props: Props) {
return <h1>Hi, my name is {props.name}!</h1>;
}
ReactDOM.render(
<NameComponent name="Martin" />,
document.getElementById('root')
);
Component
Component
Component
Component
Component
Component
Component
User info
ArticleList
Article
Today Weather
Article
I am smart 💡
function NameComponent(props) {
return <h1>{props.name}</h1>;
}
function App() {
return <NameComponent name="Martin" />
}
Hello | Hello | Hello | Hello |
---|---|---|---|
Hello | Hello | Hello | Hello |
Hello | Hello | Hello | Hello |
<Table columns={4} rows={3} />
<Table columns={5} rows={2}>
<h1>Hello</h1>
</Table>
function Table(props) {
return (
<table>
<tr>
<td>
{props.children}
</td>
</tr>
</table>
)
}
<button type="button" onClick={() => console.log('Hello')}>
Hello world
</button>
import React, { useState } from 'react';
function Counter() {
const [name, setName] = useState('nobody');
function handleGiveName(name: string) {
setName(name);
}
return <div>
My name is {name}.
<button onClick={() => handleGiveName('Martin')}>
Give me name
</button>
</div>
}
initial value
render() {
const random = Math.random();
if (random < 0.5) {
return <span>lower</span>
} else {
return <span>higher</span>
}
}
render() {
const random = Math.random();
return <span>
{random < 0.5 ? 'lower' : 'higher'}
</span>
}
import styles from './App.module.css';
function Component() {
return <div className={styles.red}>Hello</div>
}
.red {
color: red;
}
App.module.css
App.tsx
import cn from 'classnames';
import styles from './App.module.css';
...
<div className={cn({ [styles.invalid]: this.state.invalid })}>
</div>
export const MyMouse = () => {
const [mousePosition, setMousePosition] = useState({x: 0, y: 0});
useEffect(() => {
const onMouseMove = event => {
setMousePosition({
x: event.clientX,
y: event.clientY
});
};
window.addEventListener('mousemove', onMouseMove);
return () => {
window.removeEventListener('mousemove', onMouseMove);
};
}, []);
const {x, y} = mousePosition;
return (
<div>My mouse x position is {x} and y position is {y}</div>
);
};
type Props = {
doWork: () => void;
};
function ChildComponent(props: Props) {
handleClick = () => {
this.props.doWork();
}
return <button onClick={this.handleClick}>emit event</button>;
}
<ChildComponent doWork={() => console.log('triggered')} />
parent component:
child component:
funciton Component() {
const [name, setName] = useState('nobody');
const [inputName, setInputName] = useState(name);
function handleGiveName() {
setName(inputName);
}
return <>
My name is {name}.
<input
value={inputName}
onChange={(e) => setInputName(e.target.value)} />
<button onClick={() => handleGiveName()}>Give me name</button>
</>
}
import axios from 'axios';
GET https://api.chucknorris.io/jokes/random
Component
User info
JokeFetcher
Joke
I am smart 💡
data down
const useMouseMove = () => {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
useEffect(() => {
const onMouseMove = (event: any) => {
setMousePosition({
x: event.clientX,
y: event.clientY,
});
};
window.addEventListener('mousemove', onMouseMove);
return () => {
window.removeEventListener('mousemove', onMouseMove);
};
}, []);
return { x: mousePosition.x, y: mousePosition.y };
};
debugger;
const MyContext = React.createContext(false);
function App() {
return <MyContext.Provider value={true}>
<Component />
</MyContext.Provider>;
}
function Component() {
const value = useContext(MyContext);
return <div>{value}</div>;
}
const MyContext = React.createContext(false);
export function MyContextProvider({initialState, children}) {
const [state, setState] = useState(initialState);
const api = {
value: state,
changeValue: (newValue) => setState(newValue)
};
return <MyContext.Provider value={api}>
{children}
</MyContext.Provider>;
}
// used to read value from comopnent
export const useMyContext = () => useContext(MyContext);
const { value, changeValue } = useMyContext();
function Counter({children}) {
const [counter, setCounter] = useState(0);
function increment() {
setCounter(counter + 1);
}
return <>{children({counter, increment})}</>
}
function MyComponent() {
return <div>
<Counter>
{({counter, increment}) => <>
<div>Counter value: {counter}</div>
<button onClick={increment}>INC</button>
</>}
</Counter>
</div>
}
const schema = yup.object().shape({
email: yup.string().required().email(),
age: yup.number().required().positive().integer()
})
const initialValues = {
email: '',
age: 0
}
export function MyForm() {
return (
<Formik
initialValues={initialValues}
validationSchema={schema}
onSubmit={values => console.log(values)}
>
{({ handleSubmit }) => (
<form onSubmit={handleSubmit}>
<Field type="email" name="email" />
<ErrorMessage name="email" component="div" />
<Field type="number" className="error" name="age" />
<ErrorMessage name="age" className="error" component="div"/>
<button type="submit">
Submit
</button>
</form>
)}
</Formik>
);
}
function Component() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return <div>
<input ref={inputRef} />
<button onClick={handleClick}>Focus the input</button>
</div>
}
function Counter(props, ref) {
const [counter, setCounter] = useState(0);
useImperativeHandle(ref, () => ({
reset: () => setCounter(0)
}));
function handleIncrement() {
setCounter(counter+1);
}
return <div onClick={handleIncrement}>{counter}</div>;
}
const ResetableCounter = forwardRef(Counter);
function Component() {
const counterRef = useRef();
return <>
<ResetableCounter ref={counterRef} />
<button onClick={() => counterRef.current.reset()}>Reset</button>
</>
}
import { BrowserRouter, Routes, Route, Link } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Link to="/">Home</Link>
<Link to="/categories">About</Link>
<Link to="/categories/animals">Joke about animals</Link>
<Link to="/categories/history">Joke about history</Link>
<Routes>
<Route index path="/" element={<Home />} />
<Route path="/categories" element={<JokeCategories />} />
<Route path="/categories/:category" element={<Joke />} />
</Routes>
</BrowserRouter>
);
}
const navigate = useNavigate();
navigate('/categories');
import { useParams } from "react-router-dom";
function Joke() {
const params = useParams();
return (
{params.category}
);
}
const JokeMemoized = React.memo(function Joke() {
...
});
<JokeMemoized />
const useFibonacci = (n) => {
const result = useMemo(() => fibonacci(n), [n]);
return result;
}
function fibonacci(n) {
return n < 1 ? 0
: n <= 2 ? 1
: fibonacci(n - 1) + fibonacci(n - 2)
}
function Component({me}) {
const handleClick = useCallback(
(name) => console.log(`Hello ${name} and ${me}`)
, [me]);
return <ExpensiveComponent onClick={handleClick} />;
}