Bộ sưu tập cho React snippets giúp bạn hiểu mọi thứ trong 29 giây hoặc ít hơn.
Chú thích:
Tại sao lại là 29 giây hoặc ít hơn? Bài viết được dịch từ 30 seconds of React, theo nhà người ta, chúng ta có thể phải mất tới 30 giây để hiểu hết được ý nghĩa của một vấn đề nào đó, nhưng với tôi chúng ta là người Việt Nam, chúng ta phải khác biệt nên chúng ta chỉ cần 29 giây 👽 👽, và đó là lý do của tiêu đề đã bị đổi thành 29 seconds of React.
- Sử dụng Ctrl + F hoặc command + F để tìm kiếm nhanh một snippet.
- Contributions, hãy đọc contribution guide.
- Snippets viết bằng React 16.8+, sử dụng hooks. Xem thêm Hooks
Xem Prerequisites
- 30 Seconds of Code
- 30 Seconds of CSS
- 30 Seconds of Interviews
- Javascript Interview Questions Developer - My Repo 😎
- React Native Testing
- React mobx cli
Xem nội dung
Xem nội dung
Xem nội dung
Xem nội dung
Xem nội dung
Renders một danh sách các phần tử từ một mảng cho trước.
- Sử dụng giá trị của prop
isOrdered
là điều kiện để hiển thị danh sách<ol>
hoặc<ul>
. - Sử dụng
Array.prototype.map
để hiển thị các mục trongdata
như là thẻ<li>
, cung cấp mộtkey
được tạo ra từ sự kết hợp của index và giá trị của nó. - Nếu prop
isOrdered
không có sẽ hiển thị thẻ<ul>
vì nó là một danh sách mặc định.
function DataList({ isOrdered, data }) {
const list = data.map((val, i) => <li key={`${i}_${val}`}>{val}</li>);
return isOrdered ? <ol>{list}</ol> : <ul>{list}</ul>;
}
Ví dụ
const names = ['John', 'Paul', 'Mary'];
ReactDOM.render(<DataList data={names} />, document.getElementById('root'));
ReactDOM.render(<DataList data={names} isOrdered />, document.getElementById('root'));
Hiển thị một table với các hàng được tạo động từ một mảng cho trước.
- Hiển thị một phần tử
<table>
với hai cột (ID
vàValue
). - Sử dụng
Array.prototype.map
để hiển thị các mục trongdata
như là thẻ<tr>
, cung cấp mộtkey
được tạo ra từ sự kết hợp của index và giá trị của nó.
function DataTable({ data }) {
return (
<table>
<thead>
<tr>
<th>ID</th>
<th>Value</th>
</tr>
</thead>
<tbody>
{data.map((val, i) => (
<tr key={`${i}_${val}`}>
<td>{i}</td>
<td>{val}</td>
</tr>
))}
</tbody>
</table>
);
}
Ví dụ
const people = ['John', 'Jesse'];
ReactDOM.render(<DataTable data={people} />, document.getElementById('root'));
Hiển thị một table với các hàng được tạo động từ một mảng các đối tượng và một danh sách các tên thuộc tính.
- Sử dụng
Object.keys()
,Array.prototype.filter()
,Array.prototype.includes()
vàArray.prototype.reduce()
để tạo ra một mảngfilteredData
, chứa tất cả các đối tượng có các key chỉ định trongpropertyNames
. - Hiển thị một phần tử
<table>
với các cột bằng với số lượng giá trị trongpropertyNames
. - Sử dụng
Array.prototype.map
để hiển thị từng giá trị trong mảngpropertyNames
như là thẻ<th>
. - Sử dụng
Array.prototype.map
để hiển thị từng đối tượng trong mảngfilteredData
như là thẻ<tr>
, chứa một<td>
cho mỗi giá trị trong đối tượng.
function MappedTable({ data, propertyNames }) {
let filteredData = data.map(v =>
Object.keys(v)
.filter(k => propertyNames.includes(k))
.reduce((acc, key) => ((acc[key] = v[key]), acc), {})
);
return (
<table>
<thead>
<tr>
{propertyNames.map(val => (
<th key={`h_${val}`}>{val}</th>
))}
</tr>
</thead>
<tbody>
{filteredData.map((val, i) => (
<tr key={`i_${i}`}>
{propertyNames.map(p => (
<td key={`i_${i}_${p}`}>{val[p]}</td>
))}
</tr>
))}
</tbody>
</table>
);
}
Component này không hoạt động với các đối tượng lồng nhau và sẽ break nếu có các đối tượng lồng nhau bên trong bất kỳ thuộc tính nào trong propertyNames
.,<!-tags: array,object -->,<!-expertise: 1 -->
Ví dụ
const people = [
{ name: 'John', surname: 'Smith', age: 42 },
{ name: 'Adam', surname: 'Smith', gender: 'male' }
];
const propertyNames = ['name', 'surname', 'age'];
ReactDOM.render(
<MappedTable data={people} propertyNames={propertyNames} />,
document.getElementById('root')
);
Hiển thị một phần tử <input>
khi thay đổi giá trị sẽ gọi hàm callback và truyền giá trị của nó cho parent component.
- Sử dụng các giá trị mặc định ban đầu cho các tham số của phần tử
<input>
. - Hiển thị một thẻ
<input>
với các thuộc tính phù hợp và sử dụng hàmcallback
trong sự kiệnonChange
để truyền giá trị của của input cho parent component.
function Input({ callback, type = 'text', disabled = false, readOnly = false, placeholder = '' }) {
return (
<input
type={type}
disabled={disabled}
readOnly={readOnly}
placeholder={placeholder}
onChange={({ target: { value } }) => callback(value)}
/>
);
}
Ví dụ
ReactDOM.render(
<Input type="text" placeholder="Insert some text here..." callback={val => console.log(val)} />,
document.getElementById('root')
);
Hiển thị một textarea component giới hạn kí tự.
- Sử dụng hook
React.useState()
tạo một biếncontent
và xét giá trị cho nó làvalue
. Tạo hàmsetFormattedContent
, nó sẽ cắt nội dung nếu như vượt quá số lượnglimit
. - Sử dụng hook
React.useEffect()
để gọi hàmsetFormattedContent
với giá trị truyền vào là biếncontent
. - Sử dụng
<div>
để bao thẻ<textarea>
và thẻ<p>
hiển thị độ dài củacontent
và hàmonChange
của thẻ<textarea>
sẽ gọi hàmsetFormattedContent
và truyền giá trị làevent.target.value
.
function LimitedTextarea({ rows, cols, initialValue, limit }) {
const [content, setContent] = React.useState(initialValue);
const setFormattedContent = text => {
text.length > limit ? setContent(text.slice(0, limit)) : setContent(text);
};
React.useEffect(() => {
setFormattedContent(content);
}, [limit]);
return (
<div>
<textarea
rows={rows}
cols={cols}
onChange={event => setFormattedContent(event.target.value)}
value={content}
/>
<p>
{content.length}/{limit}
</p>
</div>
);
}
Ví dụ
ReactDOM.render(<LimitedTextarea limit={32} initialValue="Hello!" />, document.getElementById('root'));
Hiển thị một textarea component hạn chế từ.
- Sử dụng hook
React.useState()
để tạo biếncontent
vàwordCount
xét giá trị cho chúng làvalue
và0
. - Tạo hàm
setFormattedContent
, sử dụngString.prototype.split(' ')
để biến đầu vào thành một mảng các từ và kiểm tra kết quả , sử dụngArray.prototype.filter(Boolean)
để kiếm trađộ dài
có lớn hơnlimit
. - Nếu độ dài lớn hơn
limit
, sẽ cắt giá trị và xét lại giá trị chocontent
vàwordCount
nếu không sẽ trả về giá trị mặc định. - Sử dụng hook
React.useEffect()
để gọi hàmsetFormattedContent
với giá trị truyền vào là biếncontent
. - Sử dụng
<div>
để bọc thẻ<textarea>
và thẻ<p>
hiển thị độ dài củawordCount
và hàmonChange
của thẻ<textarea>
sẽ gọi hàmsetFormattedContent
và truyền giá trị làevent.target.value
.
function LimitedWordTextarea({ rows, cols, value, limit }) {
const [content, setContent] = React.useState(value);
const [wordCount, setWordCount] = React.useState(0);
const setFormattedContent = text => {
let words = text.split(' ');
if (words.filter(Boolean).length > limit) {
setContent(
text
.split(' ')
.slice(0, limit)
.join(' ')
);
setWordCount(limit);
} else {
setContent(text);
setWordCount(words.filter(Boolean).length);
}
};
React.useEffect(() => {
setFormattedContent(content);
}, []);
return (
<div>
<textarea
rows={rows}
cols={cols}
onChange={event => setFormattedContent(event.target.value)}
value={content}
/>
<p>
{wordCount}/{limit}
</p>
</div>
);
}
Ví dụ
ReactDOM.render(
<LimitedWordTextArea limit={5} value="Hello there!" />,
document.getElementById('root')
);
Hiển thị một danh sách checkbox sử dụng hàm callback để chọn giá trị hoặc nhiều giá trị từ parent component.
- Sử dụng
React.setState()
để tạo một biếndata
và xét giá trị khởi là từ propoptions
. - Tạo một function
toggle
được sử dụng để chuyển đổichecked
cập nhật giá trị chodata
và gọi hàmonChange
để truyền lại cho parent component. - Hiển thị phần tử
<ul>
và sử dụngArray.prototype.map()
để lặp từng phần tử trongdata
hiển thị các phần tử<li>
và<input>
bên trong. - Mỗi phần tử
<input>
có thuộc tínhtype='checkbox'
và giá trịreadOnly
.
const style = {
listContainer: {
listStyle: 'none',
paddingLeft: 0
},
itemStyle: {
cursor: 'pointer',
padding: 5
}
};
function MultiselectCheckbox({ options, onChange }) {
const [data, setData] = React.useState(options);
const toggle = item => {
data.map((_, key) => {
if (data[key].label === item.label) data[key].checked = !item.checked;
});
setData([...data]);
onChange(data);
};
return (
<ul style={style.listContainer}>
{data.map(item => {
return (
<li key={item.label} style={style.itemStyle} onClick={() => toggle(item)}>
<input readOnly type="checkbox" checked={item.checked || false} />
{item.label}
</li>
);
})}
</ul>
);
}
Ví dụ
const options = [{ label: 'Item One' }, { label: 'Item Two' }];
ReactDOM.render(
<MultiselectCheckbox
options={options}
onChange={data => {
console.log(data);
}}
/>,
document.getElementById('root')
);
Hiển thị trường nhập mật khẩu bằng cách bật tắt.
- Sử dụng hook
React.useState()
tạo một biếnshown
và cho nó giá trị làfalse
. - Sử dụng một thẻ
<div>
đê bọc<input>
và phần tử<button>
để thay đổi trạng thái"text"
và"password"
.
function PasswordRevealer({ value }) {
const [shown, setShown] = React.useState(false);
return (
<div>
<input type={shown ? 'text' : 'password'} value={value} onChange={() => {}} />
<button onClick={() => setShown(!shown)}>Show/Hide</button>
</div>
);
}
Ví dụ
ReactDOM.render(<PasswordRevealer />, document.getElementById('root'));
Hiển thị một phần tử <select>
khi thay đổi giá trị sẽ gọi hàm callback và truyền giá trị của nó cho parent component.
- Sử dụng các giá trị mặc định ban đầu cho các tham số của phần tử
<select>
. - Hiển thị một phần tử
<select>
với các thuộc tính phù hợp và sử dụng hàmcallback
làonChange
để thay đổi giá trị của textarea từ parent component. - Các giá trị của mảng
values
sẽ truyềnvalue
,text
và thuộc tínhselected
sẽ là giá trị ban đầu của phần tử<select>
.
function Select({ values, callback, disabled = false, readonly = false, selected }) {
return (
<select
disabled={disabled}
readOnly={readonly}
onChange={({ target: { value } }) => callback(value)}
>
{values.map(([value, text]) => (
<option selected={selected === value} value={value}>
{text}
</option>
))}
</select>
);
}
Ví dụ
let choices = [
['grapefruit', 'Grapefruit'],
['lime', 'Lime'],
['coconut', 'Coconut'],
['mango', 'Mango']
];
ReactDOM.render(
<Select values={choices} selected="lime" callback={val => console.log(val)} />,
document.getElementById('root')
);
Hiển thị một phần tử slider khi sử dụng sẽ gọi hàm callback và truyền giá trị của nó cho parent component.
- Sử dụng object destructuring để xét các giá trị ban đầu cho thuộc tính có phần tử
<input>
. - Hiển thị một phần tử
<input>
có type"range"
và các thuộc tính phù hợp, sử dụng hàmcallback
trong sự kiệnonChange
để truyền ngược lại giá trị cho input parent component.
function Slider({ callback, disabled = false, readOnly = false }) {
return (
<input
type="range"
disabled={disabled}
readOnly={readOnly}
onChange={({ target: { value } }) => callback(value)}
/>
);
}
Ví dụ
ReactDOM.render(<Slider callback={val => console.log(val)} />, document.getElementById('root'));
Hiển thị một phần tử <textarea>
khi thay đổi giá trị sẽ gọi hàm callback và truyền giá trị của nó cho parent component.
- Sử dụng object destructuring để xét các giá trị ban đầu cho thuộc tính có phần tử
<textarea>
. - Hiển thị một phần tử
<textarea>
với các thuộc tính phù hợp và sử dụng hàmcallback
trong sự kiệnonChange
để truyền ngược lại giá trị cho textarea parent component.
function TextArea({
callback,
cols = 20,
rows = 2,
disabled = false,
readOnly = false,
placeholder = ''
}) {
return (
<textarea
cols={cols}
rows={rows}
disabled={disabled}
readOnly={readOnly}
placeholder={placeholder}
onChange={({ target: { value } }) => callback(value)}
/>
);
}
Ví dụ
ReactDOM.render(
<TextArea placeholder="Insert some text here..." callback={val => console.log(val)} />,
document.getElementById('root')
);
Hiển thị dạng cây của một đối tượng JSON hoặc mảng có nội dung có thể thu gọn.
- Sử dụng object destructuring để xét các giá trị ban đầu cho thuộc tính
- Sử dụng giá trị của prop
toggled
để xác định trạng thái ban đầu của nội dung (được thu gọn / mở rộng). - Sử dụng hook
React.setState()
để tạo biếnisToggled
và xét cho chúng giá trị bằng với proptoggled
ban đầu. - Trả về một
<div>
để bọc nội dung của component và thẻ<span>
, sử dụng để thay đổi giá trị của biếnisToggled
. - Xác định sự xuất hiện của component, dựa trên biến
isParentToggled
,isToggled
,name
vàArray.isArray()
vớidata
. - Với mỗi phần tử trong
data
xác định nó là object hay mảng và hiển thị đệ quy một sub-tree. - Mặt khác, hiển thị một phần tử
<p>
với thuộc tính style thích hợp..
.tree-element {
margin: 0;
position: relative;
}
div.tree-element:before {
content: '';
position: absolute;
top: 24px;
left: 1px;
height: calc(100% - 48px);
border-left: 1px solid gray;
}
.toggler {
position: absolute;
top: 10px;
left: 0px;
width: 0;
height: 0;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 5px solid gray;
cursor: pointer;
}
.toggler.closed {
transform: rotate(90deg);
}
.collapsed {
display: none;
}
function TreeView({
data,
toggled = true,
name = null,
isLast = true,
isChildElement = false,
isParentToggled = true
}) {
const [isToggled, setIsToggled] = React.useState(toggled);
return (
<div
style={{ marginLeft: isChildElement ? 16 : 4 + 'px' }}
className={isParentToggled ? 'tree-element' : 'tree-element collapsed'}
>
<span
className={isToggled ? 'toggler' : 'toggler closed'}
onClick={() => setIsToggled(!isToggled)}
/>
{name ? <strong> {name}: </strong> : <span> </span>}
{Array.isArray(data) ? '[' : '{'}
{!isToggled && '...'}
{Object.keys(data).map((v, i, a) =>
typeof data[v] == 'object' ? (
<TreeView
data={data[v]}
isLast={i === a.length - 1}
name={Array.isArray(data) ? null : v}
isChildElement
isParentToggled={isParentToggled && isToggled}
/>
) : (
<p
style={{ marginLeft: 16 + 'px' }}
className={isToggled ? 'tree-element' : 'tree-element collapsed'}
>
{Array.isArray(data) ? '' : <strong>{v}: </strong>}
{data[v]}
{i === a.length - 1 ? '' : ','}
</p>
)
)}
{Array.isArray(data) ? ']' : '}'}
{!isLast ? ',' : ''}
</div>
);
}
Ví dụ
let data = {
lorem: {
ipsum: 'dolor sit',
amet: {
consectetur: 'adipiscing',
elit: [
'duis',
'vitae',
{
semper: 'orci'
},
{
est: 'sed ornare'
},
'etiam',
['laoreet', 'tincidunt'],
['vestibulum', 'ante']
]
},
ipsum: 'primis'
}
};
ReactDOM.render(<TreeView data={data} name="data" />, document.getElementById('root'));
Hiển thị một chuỗi dưới dạng plaintext, với các URL được chuyển đổi thành các phần tử <a>
phù hợp.
- Sử dụng
String.prototype.split()
vàString.prototype.match()
với regular expression để tìm URL trong chuỗi. - Trả về một
<React.Fragment>
với các URL trùng khớp được hiển thị dưới dạng các phần tử<a>
, và phần còn lại của chuỗi được hiển thị dưới dạng plaintext.
function AutoLink({ text }) {
const delimiter = /((?:https?:\/\/)?(?:(?:[a-z0-9]?(?:[a-z0-9\-]{1,61}[a-z0-9])?\.[^\.|\s])+[a-z\.]*[a-z]+|(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})(?::\d{1,5})*[a-z0-9.,_\/~#&=;%+?\-\\(\\)]*)/gi;
return (
<React.Fragment>
{text.split(delimiter).map(word => {
let match = word.match(delimiter);
if (match) {
let url = match[0];
return <a href={url.startsWith('http') ? url : `http://${url}`}>{url}</a>;
}
return word;
})}
</React.Fragment>
);
}
Ví dụ
ReactDOM.render(
<AutoLink text="foo bar baz http://example.org bar" />,
document.getElementById('root')
);
Hiển thị một menu accordion với với nội dung component có thể thu gọn.
- Xác định component
AccordionItem
, truyền nó choAccordion
và bỏ những thuộc tính không cần thiếtAccordionItem
bằng cách xác định tên của hàm trongprops.children
. - Mỗi component
AccordionItem
hiển thị một<button>
sử dụng để cập nhật lạiAccordion
thông qua hàm callbackprops.handleClick
và nội dung của component, được truyền quaprops.children
, được xác định qua biếnprops.isCollapsed
và dựa trênstyle
. - Trong component
Accordion
, sử dụng hookReact.useState()
để khởi tạo giá trị ban đầu chobindIndex
có giá trị làprops.defaultIndex
. - Sử dụng
Array.prototype.map
để hiển thị từng phần tử. - Xác định
changeItem
, sẽ được thực thi khi click vàobutton
củaAccordionItem
.changeItem
sẽ gọi hàm callback,onItemClick
và cập nhậtbindIndex
dựa trên component đã được click.
function AccordionItem(props) {
const style = {
collapsed: {
display: 'none'
},
expanded: {
display: 'block'
},
buttonStyle: {
display: 'block',
width: '100%'
}
};
return (
<div>
<button style={style.buttonStyle} onClick={() => props.handleClick()}>
{props.label}
</button>
<div
className="collapse-content"
style={props.isCollapsed ? style.collapsed : style.expanded}
aria-expanded={props.isCollapsed}
>
{props.children}
</div>
</div>
);
}
function Accordion(props) {
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
const changeItem = itemIndex => {
if (typeof props.onItemClick === 'function') props.onItemClick(itemIndex);
if (itemIndex !== bindIndex) setBindIndex(itemIndex);
};
const items = props.children.filter(item => item.type.name === 'AccordionItem');
return (
<div className="wrapper">
{items.map(({ props }) => (
<AccordionItem
isCollapsed={bindIndex === props.index}
label={props.label}
handleClick={() => changeItem(props.index)}
children={props.children}
/>
))}
</div>
);
}
Ví dụ
ReactDOM.render(
<Accordion defaultIndex="1" onItemClick={console.log}>
<AccordionItem label="A" index="1">
Lorem ipsum
</AccordionItem>
<AccordionItem label="B" index="2">
Dolor sit amet
</AccordionItem>
</Accordion>,
document.getElementById('root')
);
Hiển thị một carousel component.
- Sử dụng hook
React.setState()
để tạo biếnactive
và xét giá trị ban đầu bằng0
(vị trí đầu tiên của danh sách). - Sử dụng đối tượng
style
, để tạo từng style cho mỗi component khác nhau. - Sử dụng hook
React.useEffect()
để cập nhật giá trị củaactive
xét cho nó vị trí của item tiếp theo, sử dụngsetTimeout
. - Lấy prop
carouselItems
, để tính toán và xét giá trị chovisible
là được hiển thị hay không hiển thị. - Hiển thị những carousel item bằng cách dùng
React.cloneElement()
và truyền choprops
với các kiểu style đã được định sẵn.
function Carousel(props) {
const [active, setActive] = React.useState(0);
let scrollInterval = null;
const style = {
carousel: {
position: 'relative'
},
carouselItem: {
position: 'absolute',
visibility: 'hidden'
},
visible: {
visibility: 'visible'
}
};
React.useEffect(() => {
scrollInterval = setTimeout(() => {
const { carouselItems } = props;
setActive((active + 1) % carouselItems.length);
}, 2000);
});
const { carouselItems, ...rest } = props;
return (
<div style={style.carousel}>
{carouselItems.map((item, index) => {
const activeStyle = active === index ? style.visible : {};
return React.cloneElement(item, {
...rest,
style: {
...style.carouselItem,
...activeStyle
}
});
})}
</div>
);
}
Ví dụ
ReactDOM.render(
<Carousel
carouselItems={[
<div>carousel item 1</div>,
<div>carousel item 2</div>,
<div>carousel item 3</div>
]}
/>,
document.getElementById('root')
);
Hiển thị một component với nội dung có thể thu gọn.
- Sử dụng hook
React.setState()
để tạo biếnisCollapsed
và xét giá trị ban đầu bằngprops.collapsed
. - Sử dụng đối tượng
style
, để tạo từng style cho mỗi component khác nhau. - Sử dụng một
<div>
để bọc<button>
để cập nhật biếnisCollapsed
và nội dụng của component, thông quaprops.children
. - Xác định sự xuất hiện của nội dung, dựa trên
isCollapsed
và áp dụng các style CSS thích hợp cho mỗi đối tượng. - Cuối cùng, cập nhật giá trị của thuộc tính
aria-expanded
dựa trênisCollapsed
để cho component có thể truy cập được.
function Collapse(props) {
const [isCollapsed, setIsCollapsed] = React.useState(props.collapsed);
const style = {
collapsed: {
display: 'none'
},
expanded: {
display: 'block'
},
buttonStyle: {
display: 'block',
width: '100%'
}
};
return (
<div>
<button style={style.buttonStyle} onClick={() => setIsCollapsed(!isCollapsed)}>
{isCollapsed ? 'Show' : 'Hide'} content
</button>
<div
className="collapse-content"
style={isCollapsed ? style.collapsed : style.expanded}
aria-expanded={isCollapsed}
>
{props.children}
</div>
</div>
);
}
Ví dụ
ReactDOM.render(
<Collapse>
<h1>This is a collapse</h1>
<p>Hello world!</p>
</Collapse>,
document.getElementById('root')
);
Hiển thị đồng hồ đếm ngược in thông báo khi nó về không.
- Sử dụng object destructuring để xét giá trị mặc định prop
hours
,minutes
vàseconds
. - Sử dụng hook
React.useState()
tạo các biếntime
,paused
vàover
, xét cho chúng các giá trị ban đầu lần lượt làfalse
vàfalse
. - Tạo hàm
tick
, để cập nhật giá trị củatime
dựa trên giá trị hiện tại (tức là giảm thời gian xuống một giây). - Nếu
paused
hoặcover
làtrue
,tick
sẽ quay lại ngay lập tức. - Tạo hàm
reset
, để cập nhật các biến về trạng thái ban đầu. - Sử dụng hook
React.useEffect()
để gọi hàmtick
mỗi giây thông qua hàmsetInterval()
và sử dụngclearInterval()
để clear giá trị khi component unmounted. - Sử dụng một
<div>
bọc thẻ<p>
để hiển thị trạng thái của biếntime
, cũng như hai<button>
pause/unpause và restart. - Nếu
over
làtrue
, bộ hẹn giờ sẽ hiển thị một thông báo thay vì giá trị củatime
.
function CountDown({ hours = 0, minutes = 0, seconds = 0 }) {
const [paused, setPaused] = React.useState(false);
const [over, setOver] = React.useState(false);
const [time, setTime] = React.useState({
hours: parseInt(hours),
minutes: parseInt(minutes),
seconds: parseInt(seconds)
});
const tick = () => {
if (paused || over) return;
if (time.hours == 0 && time.minutes == 0 && time.seconds == 0) setOver(true);
else if (time.minutes == 0 && time.seconds == 0)
setTime({
hours: time.hours - 1,
minutes: 59,
seconds: 59
});
else if (time.seconds == 0)
setTime({
hours: time.hours,
minutes: time.minutes - 1,
seconds: 59
});
else
setTime({
hours: time.hours,
minutes: time.minutes,
seconds: time.seconds - 1
});
};
const reset = () => {
setTime({
hours: parseInt(hours),
minutes: parseInt(minutes),
seconds: parseInt(seconds)
});
setPaused(false);
setOver(false);
};
React.useEffect(() => {
let timerID = setInterval(() => tick(), 1000);
return () => clearInterval(timerID);
}, [tick]);
return (
<div>
<p>{`${time.hours.toString().padStart(2, '0')}:${time.minutes
.toString()
.padStart(2, '0')}:${time.seconds.toString().padStart(2, '0')}`}</p>
<div>{over ? "Time's up!" : ''}</div>
<button onClick={() => setPaused(!paused)}>{paused ? 'Resume' : 'Pause'}</button>
<button onClick={() => reset()}>Restart</button>
</div>
);
}
Ví dụ
ReactDOM.render(<CountDown hours="1" minutes="45" />, document.getElementById('root'));
Hiển thị một component kéo và thả cho một file.
- Tạo một ref gọi là
dropRef
cho component. - Sử dụng hook
React.useState()
để tạo biếndrag
vàfilename
, với giá trị ban đầu lần lượt làfalse
và''
. BiếndragCounter
vàdrag
được sử dụng để xác định một file có đang kéo hay không, cònfilename
để xác định tên file khi đã thả. - Tạo các hàm
handleDrag
,handleDragIn
,handleDragOut
vàhandleDrop
để xử lý chức năng kéo và thả, liên kết chúng với ngữ cảnh của component. - Each of the methods will handle a specific event, the listeners for which are created and removed in the
React.useEffect()
hook and its attachedcleanup()
method. - Mỗi phương thức sẽ xử lý một sự kiện cụ thể, tạo các sự kiện lắng nghe và xóa chúng trong hook
React.useEffect()
và hàmcleanup()
. handleDrag
ngăn trình duyệt mở file đã kéo,handleDragIn
vàhandleDragOut
xử lý file được kéo vào và thoát khỏi component, trong khihandleDrop
xử lý file bị thả và chuyển nó sangprops.handleDrop
.- Trả về một
<div>
với style phù hợp và sử dụngdrag
vàfilename
để xác định tên file và style. - Cuối cùng, liên kết
ref
của<div>
đã tạo vớidropRef
.
.filedrop {
min-height: 120px;
border: 3px solid #d3d3d3;
text-align: center;
font-size: 24px;
padding: 32px;
border-radius: 4px;
}
.filedrop.drag {
border: 3px dashed #1e90ff;
}
.filedrop.ready {
border: 3px solid #32cd32;
}
function FileDrop(props) {
const [drag, setDrag] = React.useState(false);
const [filename, setFilename] = React.useState('');
let dropRef = React.createRef();
let dragCounter = 0;
const handleDrag = e => {
e.preventDefault();
e.stopPropagation();
};
const handleDragIn = e => {
e.preventDefault();
e.stopPropagation();
dragCounter++;
if (e.dataTransfer.items && e.dataTransfer.items.length > 0) setDrag(true);
};
const handleDragOut = e => {
e.preventDefault();
e.stopPropagation();
dragCounter--;
if (dragCounter === 0) setDrag(false);
};
const handleDrop = e => {
e.preventDefault();
e.stopPropagation();
setDrag(false);
if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
props.handleDrop(e.dataTransfer.files[0]);
setFilename(e.dataTransfer.files[0].name);
e.dataTransfer.clearData();
dragCounter = 0;
}
};
React.useEffect(() => {
let div = dropRef.current;
div.addEventListener('dragenter', handleDragIn);
div.addEventListener('dragleave', handleDragOut);
div.addEventListener('dragover', handleDrag);
div.addEventListener('drop', handleDrop);
return function cleanup() {
div.removeEventListener('dragenter', handleDragIn);
div.removeEventListener('dragleave', handleDragOut);
div.removeEventListener('dragover', handleDrag);
div.removeEventListener('drop', handleDrop);
};
});
return (
<div
ref={dropRef}
className={drag ? 'filedrop drag' : filename ? 'filedrop ready' : 'filedrop'}
>
{filename && !drag ? <div>{filename}</div> : <div>Drop files here!</div>}
</div>
);
}
Ví dụ
ReactDOM.render(<FileDrop handleDrop={console.log} />, document.getElementById('root'));
Hiển thị một liên kết được format để gửi email.
- Lấy các giá trị component qua prop, sử dụng
email
,subject
vàbody
để tạo một thẻ<a>
với thuộc tínhhref
thích hợp. - Hiển thị nội dung của nó bằng
props.children
.
function Mailto({ email, subject, body, ...props }) {
return (
<a href={`mailto:${email}?subject=${subject || ''}&body=${body || ''}`}>{props.children}</a>
);
}
Ví dụ
ReactDOM.render(
<Mailto email="foo@bar.baz" subject="Hello" body="Hello world!">
Mail me!
</Mailto>,
document.getElementById('root')
);
Hiển thị một component Modal, có thể điều khiển thông qua các sự kiện.
Để sử dụng component, import Modal
một lần và hiển thị nó thông qua thuộc tính của isVisible
.
- Sử dụng object destructuring để xét giá trị ban đầu cho component Modal.
- Xác định
keydownHandler
, một phương thức xử lý tất cả các sự kiện bàn phím, có thể được sử dụng theo nhu cầu của bạn để làm một hành động nào đó (ví dụ: đóng Modal khi nhấn Esc). - Sử dụng hook
React.useEffect()
để thêm hoặc xóa sự kiệnkeydown
, khi gọi hàmkeydownHandler
. - Sử dụng prop
isVisible
để xác định Modal có được hiển thị hay không. - Sử dụng CSS để style cho Modal.
.modal {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right:0;
width: 100%;
z-index: 9999;
display: flex;
align-items: center;
justify-content: center;
background-color: rgba(0, 0, 0, 0.25);
animation-name: appear;
animation-duration: 300ms;
}
.modal-dialog{
width: 100%;
max-width: 550px;
background: white;
position: relative;
margin: 0 20px;
max-height: calc(100vh - 40px);
text-align: left;
display: flex;
flex-direction: column;
overflow:hidden;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19);
-webkit-animation-name: animatetop;
-webkit-animation-duration: 0.4s;
animation-name: slide-in;
animation-duration: 0.5s;
}
.modal-header,.modal-footer{
display: flex;
align-items: center;
padding: 1rem;
}
.modal-header{
border-bottom: 1px solid #dbdbdb;
justify-content: space-between;
}
.modal-footer{
border-top: 1px solid #dbdbdb;
justify-content: flex-end;
}
.modal-close{
cursor: pointer;
padding: 1rem;
margin: -1rem -1rem -1rem auto;
}
.modal-body{
overflow: auto;
}
.modal-content{
padding: 1rem;
}
@keyframes appear {
from {opacity: 0;}
to {opacity: 1;}
}
@keyframes slide-in {
from {transform: translateY(-150px);}
to { transform: translateY(0);}
}
function Modal({ isVisible = false, title, content, footer, onClose }){
React.useEffect(() => {
document.addEventListener('keydown', keydownHandler);
return () => document.removeEventListener('keydown', keydownHandler);
});
function keydownHandler({ key }) {
switch (key) {
case 'Escape': onClose(); break;
default:
}
}
return !isVisible ? null : (
<div className="modal" onClick={onClose}>
<div className="modal-dialog" onClick={e => e.stopPropagation()}>
<div className="modal-header">
<h3 className="modal-title">{title}</h3>
<span className="modal-close" onClick={onClose}>×</span>
</div>
<div className="modal-body">
<div className="modal-content">{ content }</div>
</div>
{footer && <div className="modal-footer">{footer}</div>}
</div>
</div>
)
}
Ví dụ
//Add the component to the render function
function App() {
const [ isModal, setModal] = React.useState(false);
return (
<React.Fragment>
<button onClick={()=> setModal(true)}>Click Here</button>
<Modal
isVisible={ isModal }
title= "Modal Title"
content = {<p>Add your content here</p>}
footer = {<button>Cancel</button>}
onClose ={()=> setModal(false)}
/>
</React.Fragment>
)
}
ReactDOM.render( <App/>, document.getElementById('root'));
Hiển thị một star rating component.
- Component
Star
sẽ hiển thị từng ngôi sao riêng lẻ với style phù hợp dựa vào trạng thái của parent component. - Trong component
StarRating
, sử dụng hookReact.useState()
để xác định trạng thái của biếnrating
vàselection
với giá trị mặc định ban đầu làprops.rating
(hoặc0
nếu như không tồn tại) và0
. - Tạo một hàm,
hoverOver
, để cập nhật giá trịselected
vàrating
. - Tạo một
<div>
để bọc những component<Star>
, sử dụngArray.prototype.map
để hiển thị 5 phần tử, được tạo bằngArray.from
, và hàmonMouseLeave
sẽ xétselection
thành0
, hàmonClick
sẽ xét giá trị chorating
và hàmonMouseOver
xét choselection
bằng giá trị thuộc tính củastar-id
củaevent.target
. - Cuối cùng, truyền các giá trị cho component
<Star>
(starId
vàmarked
).
function Star({ marked, starId }) {
return (
<span star-id={starId} style={{ color: '#ff9933' }} role="button">
{marked ? '\u2605' : '\u2606'}
</span>
);
}
function StarRating(props) {
const [rating, setRating] = React.useState(typeof props.rating == 'number' ? props.rating : 0);
const [selection, setSelection] = React.useState(0);
const hoverOver = event => {
let val = 0;
if (event && event.target && event.target.getAttribute('star-id'))
val = event.target.getAttribute('star-id');
setSelection(val);
};
return (
<div
onMouseOut={() => hoverOver(null)}
onClick={(event) => setRating(event.target.getAttribute('star-id') || rating)}
onMouseOver={hoverOver}
>
{Array.from({ length: 5 }, (v, i) => (
<Star
starId={i + 1}
key={`star_${i + 1} `}
marked={selection ? selection >= i + 1 : rating >= i + 1}
/>
))}
</div>
);
}
Ví dụ
ReactDOM.render(<StarRating />, document.getElementById('root'));
ReactDOM.render(<StarRating rating={2} />, document.getElementById('root'));
Hiển thị một tab menu và xem component.
- Component
TabItem
, sẽ hiển thị các giá trị cần thiết thông qua tên trong hàmprops.children
. - Sử dụng hook
React.useState()
để tạo biếnbindIndex
có giá trị ban đầu bằngprops.defaultIndex
. - Sử dụng
Array.prototype.map
để hiển thị cáctab-menu
vàtab-view
. - Hàm
changeTab
, sẽ chạy khi onlcik vào<button>
từtab-menu
. - Hàm
changeTab
sẽ gọi lại,onTabClick
và cập nhậtbindIndex
, từ đó thì hiển thị lại, và thay đổistyle
vàclassName
của itemtab-view
và buttontab-menu
theoindex
của chúng.
.tab-menu > button {
cursor: pointer;
padding: 8px 16px;
border: 0;
border-bottom: 2px solid transparent;
background: none;
}
.tab-menu > button.focus {
border-bottom: 2px solid #007bef;
}
.tab-menu > button:hover {
border-bottom: 2px solid #007bef;
}
function TabItem(props) {
return <div {...props} />;
}
function Tabs(props) {
const [bindIndex, setBindIndex] = React.useState(props.defaultIndex);
const changeTab = newIndex => {
if (typeof props.onTabClick === 'function') props.onTabClick(newIndex);
setBindIndex(newIndex);
};
const items = props.children.filter(item => item.type.name === 'TabItem');
return (
<div className="wrapper">
<div className="tab-menu">
{items.map(({ props: { index, label } }) => (
<button onClick={() => changeTab(index)} className={bindIndex === index ? 'focus' : ''}>
{label}
</button>
))}
</div>
<div className="tab-view">
{items.map(({ props }) => (
<div
{...props}
className="tab-view_item"
key={props.index}
style={{ display: bindIndex === props.index ? 'block' : 'none' }}
/>
))}
</div>
</div>
);
}
Ví dụ
ReactDOM.render(
<Tabs defaultIndex="1" onTabClick={console.log}>
<TabItem label="A" index="1">
Lorem ipsum
</TabItem>
<TabItem label="B" index="2">
Dolor sit amet
</TabItem>
</Tabs>,
document.getElementById('root')
);
Hiển thị một ticker component.
- Sử dụng
React.useState()
để khởi tạo biếnticker
và giá trị mặc định là0
. - Hàm
tick
vàreset
sẽ tăng theotimer
dựa trêninterval
và resetinterval
tương ứng. - Trả về một
<div>
với hai phần tử<button>
, mỗi phần tử gọi lần lượt làtick
vàreset
.
// https://overreacted.io/making-setinterval-declarative-with-react-hooks/
function useInterval(callback, delay) {
const savedCallback = React.useRef();
// Remember the latest callback.
React.useEffect(() => {
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
React.useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
function Ticker(props) {
const [ticker, setTicker] = React.useState(0);
const [isRunning, setIsRunning] = React.useState(false);
useInterval(
() => {
if (ticker < props.times) setTicker(ticker + 1);
else setIsRunning(false);
},
isRunning ? props.interval : null
);
return (
<div>
<span style={{ fontSize: 100 }}>{ticker}</span>
<button onClick={() => setIsRunning(true)}>Tick!</button>
<button
onClick={() => {
setIsRunning(false);
setTicker(0);
}}
>
Reset
</button>
</div>
);
}
Ví dụ
ReactDOM.render(<Ticker times={5} interval={1000} />, document.getElementById('root'));
Hiển thị một toggle component.
- Sử dụng
React.useState()
để khởi tạo biếnisToggleOn
và giá trị mặc định làfalse
. - Sử dụng
style
để tạo kiểu cho mỗi component khác nhau. - Trả về một
<button>
để làm thay đổi giá trịisToggledOn
khi gọi sự kiệnonClick
và dựa trên biếnisToggledOn
sẽ thay đổi giá trị CSS củastyle
button.
function Toggle(props) {
const [isToggleOn, setIsToggleOn] = React.useState(false);
style = {
on: {
backgroundColor: 'green'
},
off: {
backgroundColor: 'grey'
}
};
return (
<button onClick={() => setIsToggleOn(!isToggleOn)} style={isToggleOn ? style.on : style.off}>
{isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
Ví dụ
ReactDOM.render(<Toggle />, document.getElementById('root'));
Hiển thị một tooltip component.
- Sử dụng
React.useState()
để khởi tạo biếnshow
và giá trị mặc định làfalse
. - Trả về một thẻ
<div>
có chứa<div>
sẽ là tooltip và propchildren
truyền cho component. - Hàm
onMouseEnter
vàonMouseLeave
sẽ làm thay đổi giá trị của biếnshow
.
.tooltip {
position: relative;
background: rgba(0, 0, 0, 0.7);
color: white;
visibility: hidden;
padding: 5px;
border-radius: 5px;
}
.tooltip-arrow {
position: absolute;
top: 100%;
left: 50%;
border-width: 5px;
border-style: solid;
border-color: rgba(0, 0, 0, 0.7) transparent transparent;
}
function Tooltip({ children, text, ...rest }) {
const [show, setShow] = React.useState(false);
return (
<div>
<div className="tooltip" style={show ? { visibility: 'visible' } : {}}>
{text}
<span className="tooltip-arrow" />
</div>
<div {...rest} onMouseEnter={() => setShow(true)} onMouseLeave={() => setShow(false)}>
{children}
</div>
</div>
);
}
Ví dụ
ReactDOM.render(
<Tooltip text="Simple tooltip">
<button>Hover me!</button>
</Tooltip>,
document.getElementById('root')
);
Đây là repository đang hoàn thiện. Nếu bạn muốn trở thành contribute, hãy PRs hoặc tạo issues nếu như bạn cần hỗ trợ !