1 trong 3 framework phổ biến nhất hiện nay (bên cạnh Angular và VueJS)
khuyến cáo: https://codesandbox.io
khác:
import React, { useState } from 'react';
function CounterApp() {
const [count, setCount] = useState(0);
return (
<div>
count: {count}
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
export default CounterApp;
import React, { useState } from 'react';
function SlideshowApp() {
const [img, setImg] = useState(0);
return (
<div>
<button onClick={() => setImg(0)}>start</button>
<button onClick={() => setImg(img - 1)}>prev</button>
<img
src={`https://picsum.photos/200?image=${img}`}
alt="slideshow"
/>
<button onClick={() => setImg(img + 1)}>next</button>
</div>
);
}
export default SlideshowApp;
tùy vào lựa chọn:
Để phân biệt component với các thẻ thông thường của HTML, tên component bắt đầu bằng chữ cái viết hoa
JSX = cú pháp của React
<div>Một năm có {365 * 24} giờ</div>
Task:
<div>
hiển thị ngày:
const dateString = new Date().toLocaleDateString();
<div>ngày hiện tại: {dateString}</div>
sấp hay ngửa:
<div>{Math.random() > 0.5 ? 'sấp' : 'ngửa'}</div>
chúng ta cũng có thể chuyển từ XML sang JS:
<a href={'https://en.wikipedia.org/wiki/' + articleName}>
bài viết
</a>
Lưu ý: Không có kí tự nháy kép xung quanh giá trị của href
const hello = () => {
console.log('hello world');
// ...
};
<button onClick={hello}>Say Hello</button>
Danh sách các browser event: https://www.w3schools.com/jsref/dom_obj_event.asp
Lưu ý: Một event handler phải là function (chứ không phải việc gọi function)
Đúng:
<button onClick={alert}>Say something</button>
Không đúng:
<button onClick={alert('hello')}>Say Hello</button>
Đúng:
<button onClick={() => alert('hello')}>Say Hello</button>
Nhiều phần tử có thể được thêm vào bằng mảng (array):
const elements = [
<div>dota</div>,
<div>lol</div>,
<div>csgo</div>,
];
<h1>3 phần tử:</h1>
{ elements }
Ví dụ: Hiển thị tất cả các tên phương thức của React trong element ul
const reactMethods = [];
for (let method in React) {
reactMethods.push(<li>{method}</li>);
}
<div>
React Methods:
<ul>{reactMethods}</ul>
</div>
Component có thể có state nội tại
State có thể được tham chiếu trong template, giao diện sẽ được tự động cập nhật nếu state có thay đổi.
Trong function component, ta sử dụng state hook:
import { useState } from 'react';
useState
có thể được gọi lại (nhiều lần) trong function component
useState
nhận 1 tham số đầu vào: giá trị đầu tiên được khởi tạouseState
sẽ trả về một mảng gồm 2 phần tử: state hiện tại và một hàm để set giá trị mới cho stateconst App = () => {
const [count, setCount] = useState(0);
const [title, setTitle] = useState('React app');
return ...
};
Chúng ta sẽ thêm một nút vào app. Ban đầu trên nút sẽ hiển thị số 0, sau mỗi click thì tăng lên 1.
const Counter = () => {
const [count, setCount] = useState(0);
return (
<button
onClick={() => {
setCount(count + 1);
}}
>
{count}
</button>
);
};
Làm một trang slideshow hiển thị ảnh như dưới đây:
https://picsum.photos/200?image=10
JavaScript là ngôn ngữ đã được chuẩn hóa bởi tổ chức ECMAScript (ES)
ES5: Hỗ trợ bởi tất cả các trình duyệt, kể cả Internet Explorer
Từ 2015: chuẩn này được cập nhật vào tháng 6 mỗi năm (ES2015, ES2016, ...)
JS hiện đại được biên dịch về ES5 qua các công cụ như Babel, Webpack,...
import và export có tên:
// mymodule.js
const foo = 1;
const bar = 2;
const baz = 3;
export { foo, bar, baz };
// index.js
import { foo, bar } from 'mymodule.js';
Chỉ có thể có 1 default export
// mymodule.js
const foo = 1;
const bar = 2;
const baz = 3;
export { foo, bar, baz };
const main = 0;
export default main;
// index.js
import main, { foo, bar } from 'mymodule.js';
Các công cụ bundler như webpack có thể hơi khác so với chuẩn import Javascript thông thường:
.js
index.js
const multiply = (a, b) => {
return a * b;
};
const multiply = (a, b) => a * b;
nếu ta muốn return ra object trực tiếp: bọc nó trong ngoặc tròn
const getState = () => ({
loggedIn: true,
userName: 'user',
});
const name = 'Mike';
const greeting = `Hello, ${name}!
This is ES2015!`;
Dấu chẩm phẩy cuối câu lệnh trong JavaScript hoàn toàn không bắt buộc.
const a = 3
console.log(a)
được xem như là:
const a = 3;
console.log(a);
Tuy nhiên cũng cần lưu ý một số trường hợp như
const Foo = () => {
return
<div>
<h1>some content</h1>
</div>;
};
sẽ bị coi là return sớm và có thể lỗi:
const Foo = () => {
return;
<div>
<h1>some content</h1>
</div>;
};
const [result, errors] = someComputation();
// đổi giá trị
let a = 1;
let b = 2;
[a, b] = [b, a];
const person = { name: 'John', age: 48 };
const { name, age } = person;
const TodoItem = ({ title, completed }) => (
<div>
{completed ? 'DONE: ' : 'TODO: '}
{title}
</div>
);
const squares = [1, 4, 9];
const moreSquares = [...squares, 16, 25];
// moreSquares: [1, 4, 9, 16, 25]
const person = {
firstName: 'Joe',
lastName: 'Doe',
age: 31,
};
const newPerson = { ...person, email: '[email protected]', age: 32 };
// {firstName: 'Joe', lastName: 'Doe', email: '[email protected]', age: 32}
Là 2 phương thức trong functional programming
const myNumbers = [1, 2, 3, 4];
const tripledNumbers = myNumbers.map((n) => 3 * n);
// [3, 6, 9, 12]
const myNumbers = [1, 2, 3, 4];
const isEven = (n) => n % 2 === 0;
const evenNumbers = myNumbers.filter(isEven);
// [2, 4]
Nhiều cách:
Một số câu lệnh có thể dùng để tạo project có tên "todolist":
npx create-react-app todolist
npx create-react-app todolist --template typescript
npx create-react-app todolist --template cra-template-pwa-typescript
npx create-next-app todolist
npx create-next-app todolist --example with-typescript
npx gatsby new
xem thêm: https://reactjs.org/docs/create-a-new-react-app.html
Có rất nhiều thứ có thể config trong quá trình tạo project:
public/index.html
, src/index.js
: các file đầu vàoApp.js
, App.css
: Component App gốcnode_modules
: thư việnTrong thư mục project:
npm run start
(or npm start
): Chạy server dev để có thể truy cập qua localhost
npm run build
: tiến hành build (phục vụ cho quá trình dev)Ghi chú:
Đôi khi server dev sẽ báo lỗi mặc dù đã sửa. Có thể khắc phục bằng cách nhấn Ctrl + C và chạy lại.
Immutability: Một trong những khái niệm quan trọng trong functional programming, được sử dụng trong React / Redux
Dữ liệu không được sửa đổi trực tiếp, mà sẽ có dữ liệu khác tạo ra, biến đổi từ dữ liệu cũ (có thể sẽ thay thế dữ liệu cũ)
Khi có object hoặc array, ta thường thử thay đổi chúng trực tiếp
và điều này là không nên, React sẽ không nhận ra thay đổi và sẽ không render lại view.
State nên được xem như một dạng dữ liệu bất biến (immutable).
Khi setState
được gọi, React sẽ so sánh
Nếu state cũ và state mới đều tham chiếu (refer) đến cùng một object (dù có thay đổi), component cũng sẽ không được render lại.
demo (xem thêm: https://codesandbox.io/s/exciting-dust-w7hni):
function App() {
const [numbers, setNumbers] = useState([0, 1, 2]);
return (
<div>
<div>{JSON.stringify(numbers)}</div>
<button
onClick={() => {
// không hợp lệ - sửa state
numbers.push(numbers.length);
setNumbers(numbers);
}}
>
add (mutate)
</button>
<button
onClick={() => {
// hợp lệ - thay state
setNumbers([...numbers, numbers.length]);
}}
>
add (replace)
</button>
</div>
);
}
code dạng như sau sẽ không được chấp nhận khi thay đổi state và React sẽ không render lại:
todos[0].completed = true;
todos.push({ title: 'study', completed: false });
Dữ liệu ban đầu:
const names = ['Alice', 'Bob', 'Mallory'];
mutation: Cách này sẽ biến đổi mảng gốc
names.push('Dan');
không có mutation: Tạo ra array mới (spread syntax)
const newNames = [...names, 'Dan'];
Dữ liệu ban đầu:
const user = {
name: 'john'
email: '[email protected]'
}
mutation: cái này sẽ biến đổi object
user.email = '[email protected]';
không có mutation: tạo ra object mới (spread syntax)
const newUser = { ...user, email: '[email protected]' };
immer.js là một thư viện giúp làm việc với dữ liệu bất biến (immutable)
và được Redux khuyến nghị sử dụng
đoạn code này sẽ biến đổi mảng todos:
todos[0].completed = true;
todos.push({ title: 'study', completed: false });
tránh biến đổi trực tiếp, bằng cách dùng immer.js
import produce from 'immer';
const newTodos = produce(todos, (todosDraft) => {
todosDraft[0].completed = true;
todosDraft.push({ title: 'study', completed: false });
});
Trong React, thẻ <input>
khá đặc biệt:
Thuộc tính (property, .value
) có thể được thay đổi trực tiếp bởi người dùng.
Do đó sẽ có một số phương diện của UI state sẽ không được nhận bởi React state.
Đây là cách ta điều khiển và theo dõi giá trị của input
trong state:
const [inputText, setInputText] = useState('');
<input
value={inputText}
onChange={(event) => {
setInputText(event.target.value);
}}
/>
Hành vi mặc định của một form khi được submit: Gửi thẳng data lên server
Ta sẽ thay thế hành vi đó:
<form
onSubmit={(event) => {
event.preventDefault(); // Quan trọng
// handle submit
}}
>
<input />
</form>
Form validation thủ công:
const NewsletterRegistration = () => {
const [email, setEmail] = useState('');
const [emailEdited, setEmailEdited] = useState(false);
const emailInvalid = !isEmail(email);
return (
<form
onSubmit={(e) => {
e.preventDefault();
console.log(email);
}}
>
<input
type="email"
name="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
onBlur={() => setEmailEdited(true)}
/>
<button disabled={emailInvalid}>subscribe</button>
{emailEdited && emailInvalid ? (
<div>email không hợp lệ</div>
) : null}
</form>
);
};
const isEmail = (email) =>
email.match(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i);
các tính năng:
mục lục:
Một số thuộc tính có tên khác với HTML:
className
(thay cho class
)onClick
(thay cho onclick
)htmlFor
(thay cho for
)Ví dụ: CSS class
<li
className={
isCompleted ? 'todoitem completed' : 'todoitem'
}
>
[...]
</li>
Có rất nhiều thư viện giúp cho việc tạo className động, ví dụ: classnames
Trong JSX, thuộc tính style nhận đầu vào là object:
<div
style={{
backgroundColor: '#333',
fontSize: getFontSize(),
}}
/>
Xây dựng một danh sách HTML (thẻ ul
) từ data sau:
const initialTodos = [
{ id: 1, title: 'groceries', completed: false },
{ id: 2, title: 'cooking', completed: true },
{ id: 3, title: 'gardening', completed: false },
];
Ta có thể sinh ra mảng các phần tử JSX bằng .map
:
const TodoApp = () => {
const [todos, setTodos] = useState(initialTodos);
return (
<ul>
{todos.map((todo) => (
<li>{todo.title}</li>
))}
</ul>
);
};
Với đoạn code trên, console sẽ cảnh báo đỏ vì thiếu thuộc tính key
, ta thêm vào như sau:
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
<div>{Math.random() > 0.5 ? 'heads' : 'tails'}</div>
let face;
if (Math.random() > 0.5) {
face = 'heads';
} else {
face = 'tails';
}
return <div>{face}</div>;
<div>{state.hasError && state.errorMessage}</div>
Toán tử &&
trong JavaScript: Dùng để rút gọn biểu thức
true && 'my message'; // 'my message'
false && 'my message'; // false
Các đoạn code HTML dưới đây là như nhau (hiển thị một dấu cách giữa các ảnh):
<img src="foo.png" /> <img src="bar.png" />
<img src="foo.png" /> <img src="bar.png" />
<img src="foo.png" />
<img src="bar.png" />
quy tắc trong JSX:
Khoảng trắng giữa 2 element trên 1 dòng sẽ được tính như 1 khoảng trắng.
Khoảng trắng giữa 2 element trong 2 dòng khác nhau sẽ được bỏ qua
Một khoảng trắng:
<img src="foo.png" /> <img src="bar.png" />
Không có khoảng trắng:
<img src="foo.png" />
<img src="bar.png" />
"ép" hiển thị khoảng trắng trong JSX:
<img src="foo.png" />{" "}
<img src="bar.png" />
Comment có thể được viết dưới dạng JavaScript:
a = <div>Hello World!{/*this is a comment*/}</div>;
Fragment cho phép return nhiều element trong một component mà không cần có thẻ nào khác bao ngoài (thường là div
):
return (
<>
<td>Hello</td>
<td>World</td>
</>
);
hoặc
return (
<React.Fragment>
<td>Hello</td>
<td>World</td>
</React.Fragment>
);
<div>
, <img>
, <MyComponent>
)const element = <a href="https://google.com">Google</a>;
được compile thành:
const element = React.createElement(
'a',
{ href: 'https://google.com' },
'Google'
);
const element = (
<MyComponent prop1={1} prop2={2}>
<div>test 1</div>
<div>test 2</div>
</MyComponent>
);
được compile thành:
const element = React.createElement(
MyComponent,
{ prop1: 1, prop2: 2 },
React.createElement('div', null, 'test 1'),
React.createElement('div', null, 'test 2')
);
Tạo một app todolist với các chức năng sau:
React app có thể được chia thành các component nhằm:
Component cha có thể "truyền" state xuống component con.
Component con có thể kích hoạt event để component cha cập nhật.
Nếu nhiều component cần truy cập state giống nhau, thường ta sẽ đặt state ở component cha chung. Sau đó truyền vào các component con dưới dạng props. Xem thêm: React docs: lifting state up
Có 2 cách phổ biến:
Để phân biệt component với các tag HTML khác, component phải được đặt tên chữ cái đầu viết hoa.
Các component có sẵn theo chuẩn material design của Google.
Xem thêm thông tin ở phần Installation và Usage trên trang chủ
Xem thêm thông tin ở phần Getting Started và Components trên trang chủ
ví dụ:
<ProgressBar value={0.75} color="green" />
Ví dụ khởi tạo component (TypeScript) với props:
type Props = { value: number; color?: string };
const ProgressBar = (props: Props) => {
// ...
};
Ví dụ khởi tạo component với props object destructuring:
const ProgressBar = ({ value, color }: Props) => {
// ...
};