main
js 119 lines 2.74 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 * @flow
8 */
9
10 import * as React from 'react';
11 import {Fragment, useCallback, useState} from 'react';
12 import ListItem from './ListItem';
13 import styles from './List.css';
14
15 export type Item = {
16 id: number,
17 isComplete: boolean,
18 text: string,
19 };
20
21 type Props = {};
22
23 export default function List(props: Props): React.Node {
24 const [newItemText, setNewItemText] = useState<string>('');
25 const [items, setItems] = useState<Array<Item>>([
26 {id: 1, isComplete: true, text: 'First'},
27 {id: 2, isComplete: true, text: 'Second'},
28 {id: 3, isComplete: false, text: 'Third'},
29 ]);
30 const [uid, setUID] = useState<number>(4);
31
32 const handleClick = useCallback(() => {
33 if (newItemText !== '') {
34 setItems([
35 ...items,
36 {
37 id: uid,
38 isComplete: false,
39 text: newItemText,
40 },
41 ]);
42 setUID(uid + 1);
43 setNewItemText('');
44 }
45 }, [newItemText, items, uid]);
46
47 const handleKeyPress = useCallback(
48 (event: $FlowFixMe) => {
49 if (event.key === 'Enter') {
50 handleClick();
51 }
52 },
53 [handleClick],
54 );
55
56 const handleChange = useCallback(
57 (event: $FlowFixMe) => {
58 setNewItemText(event.currentTarget.value);
59 },
60 [setNewItemText],
61 );
62
63 const removeItem = useCallback(
64 (itemToRemove: $FlowFixMe) =>
65 setItems(items.filter(item => item !== itemToRemove)),
66 [items],
67 );
68
69 const toggleItem = useCallback(
70 (itemToToggle: $FlowFixMe) => {
71 // Dont use indexOf()
72 // because editing props in DevTools creates a new Object.
73 const index = items.findIndex(item => item.id === itemToToggle.id);
74
75 setItems(
76 items
77 .slice(0, index)
78 .concat({
79 ...itemToToggle,
80 isComplete: !itemToToggle.isComplete,
81 })
82 .concat(items.slice(index + 1)),
83 );
84 },
85 [items],
86 );
87
88 return (
89 <Fragment>
90 <h1>List</h1>
91 <input
92 type="text"
93 placeholder="New list item..."
94 className={styles.Input}
95 value={newItemText}
96 onChange={handleChange}
97 onKeyPress={handleKeyPress}
98 />
99 <button
100 className={styles.IconButton}
101 disabled={newItemText === ''}
102 onClick={handleClick}>
103 <span role="img" aria-label="Add item">
104
105 </span>
106 </button>
107 <ul className={styles.List}>
108 {items.map(item => (
109 <ListItem
110 key={item.id}
111 item={item}
112 removeItem={removeItem}
113 toggleItem={toggleItem}
114 />
115 ))}
116 </ul>
117 </Fragment>
118 );
119 }