Lorem ipsum dolor sit amet, consectetur adipiscing elit lobortis arcu enim urna adipiscing praesent velit viverra sit semper lorem eu cursus vel hendrerit elementum morbi curabitur etiam nibh justo, lorem aliquet donec sed sit mi at ante massa mattis.
Lorem ipsum dolor sit amet, consectetur adipiscing elit ut aliquam, purus sit amet luctus venenatis, lectus magna fringilla urna, porttitor rhoncus dolor purus non enim praesent elementum facilisis leo, vel fringilla est ullamcorper eget nulla facilisi etiam dignissim diam quis enim lobortis scelerisque fermentum dui faucibus in ornare quam viverra orci sagittis eu volutpat odio facilisis mauris sit amet massa vitae tortor condimentum lacinia quis vel eros donec ac odio tempor orci dapibus ultrices in iaculis nunc sed augue lacus
At risus viverra adipiscing at in tellus integer feugiat nisl pretium fusce id velit ut tortor sagittis orci a scelerisque purus semper eget at lectus urna duis convallis. porta nibh venenatis cras sed felis eget neque laoreet libero id faucibus nisl donec pretium vulputate sapien nec sagittis aliquam nunc lobortis mattis aliquam faucibus purus in.
Nisi quis eleifend quam adipiscing vitae aliquet bibendum enim facilisis gravida neque. Velit euismod in pellentesque massa placerat volutpat lacus laoreet non curabitur gravida odio aenean sed adipiscing diam donec adipiscing tristique risus. amet est placerat in egestas erat imperdiet sed euismod nisi.
“Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum”
Eget lorem dolor sed viverra ipsum nunc aliquet bibendum felis donec et odio pellentesque diam volutpat commodo sed egestas aliquam sem fringilla ut morbi tincidunt augue interdum velit euismod eu tincidunt tortor aliquam nulla facilisi aenean sed adipiscing diam donec adipiscing ut lectus arcu bibendum at varius vel pharetra nibh venenatis cras sed felis eget dolor cosnectur drolo.
React Hooks isn’t a new thing, however there’s still alot to learn and many ways to apply them. The subject of combining different hooks such as useState
and useEffect
is also a point developers usually struggle with as they’re going into React Hooks.
The power of Hooks comes into play especially when building slim, functional components which require managing some internal state. Hooks allow doing exactly that – without the overhead of Class components, Constructors and full lifecycle management methods.
Take a look at such an app utilizing hooks for its state management.
1const App = () => {
2 const [items, setItems] = useState([
3 { id: 1, title: 'Tomatoes' },
4 { id: 2, title: 'Onions' },
5 { id: 3, title: 'Cucumbers' },
6 { id: 4, title: 'Olives' },
7 { id: 5, title: 'Letuce' },
8 { id: 6, title: 'Peanutes' },
9 ]);
10
11 const [availableItems, setAvailableItems] = useState([1, 2, 4, 6]);
12
13 const discountedItems = [
14 { id: 1, percentage: 30 },
15 { id: 6, percentage: 10 },
16 ];
17
18 const addItem = () => {
19 const id = items.slice(-1)[0].id + 1;
20 const newItems = [...items, { id, title: `Ingredient #${id}` }];
21 setItems(newItems);
22 const newAvailItems = [...availableItems, id];
23 setAvailableItems(newAvailItems);
24 };
25
26 return (
27 <div className="App">
28 <h1>Pick ingredients for your salad:</h1>
29 <Menu
30 items={items}
31 availableItems={availableItems}
32 discountedItems={discountedItems}
33 />
34 <div>
35 <button onClick={addItem}>Add Item</button>
36 </div>
37 </div>
38 );
39}
The App holds a list of items
– these are Salad ingredients – Let’s say we got them from the server etc. It also holds a list of availableItems
and discountedItems
.
It’s rendering <Menu>
component to display the items and allows the user to tick / untick items. Through the addItem
method The user can also add an item / ingredient. For the sake of the example each new ingredient has an autogenerated title.
The app is using the useState
hook twice – first to manage the list of Items and then to manage the list of Available Items as a new item is added and becomes available.
So far that was the everyday use of setState. Let’s take a look at the internal components – Menu
and its children.
const Menu = ({ items, discountedItems, availableItems }) => {
const [activeItems, setActiveItems] = useState([]);
const [ingredients, setIngredients] = useState([]);
useEffect(() => {
const newIngredients = items.map(item => {
// Check if item is available. Return true or false
const isAvailable = availableItems.indexOf(item.id) > -1;
if (isAvailable) {
// Check if item is discounted. If so, return the discount
const discount = discountedItems.find(disItem => disItem.id === item.id);
return { ...item, discount: discount && discount.percentage };
}
return false;
}).filter(i => i);
setIngredients(newIngredients);
}, [items]);
const toggleItem = (item, { target: { checked } }) => {
// Remove the toggled item from the array
const newActiveItems = activeItems.filter(i => i !== item.id);
if (checked) {
// If item is checked, add the toggled item to the array
newActiveItems.push(item.id);
}
// Set the new activeItems array
setActiveItems(newActiveItems);
}
return (<ItemsList
items={ingredients}
activeItems={activeItems}
toggleItem={toggleItem} />);
}
The <Menu>
is getting Three props – items
, discountedItems
and availableItems
. In order to render its child, <ItemsList>
, which only gets item
and activeItems
props, the <Menu>
component has to merge its props into a single ingredients
variable to pass onto <ItemsList>
. This is done using the useEffect
hook, which runs the unification logic and then calls setIngredients
to persist it in the state.
useEffect
?useEffect
does what it says – creates side effects. This makes it a key lifecycle method which has to play well with the rendering cycle of the component. We don’t necessarily want useEffect to run on every render of our component. This second argument of useEffect
helps doing just that.
The basics for this are:
componentDidUpdate
, only it runs during the first render as well).componentDidMount
).componentWillRecieveProps
).In our example the effect gets [items]
as the second argument, corresponding to the 3rd use case above. This means whenever the items
prop is modified, our effect will run.
As we’re updating the component’s state inside the effect (by calling setIngredients
), we cannot simply omit the second argument as we’ll immediatly go into an infinite loop – similar to calling setState
inside componentDidMount
with no conditions (that’s a no-no!). And as we’d like the effect to run whenever items
is modified (user adds a new ingerdient), we cannot supply an empty array as the effect will then run only once.
Finally, the core part of our UI is rendered by Two final components – <ItemsList>
which renders <MenuItem>
.
const ItemsList = ({ items, activeItems, toggleItem }) => (
<Fragment>
<div>Checked Items</div>
<ul>{items.filter(item => activeItems.indexOf(item.id) > -1).map(item =>
<li>
<MenuItem
item={item}
checked
onChange={e => toggleItem(item, e)}
/>
</li>)
}</ul>
<div>Available Items</div>
<ul>{items.filter(item => activeItems.indexOf(item.id) === -1).map(item =>
<li>
<MenuItem
item={item}
checked={activeItems.indexOf(item.id) > -1}
onChange={e => toggleItem(item, e)}
/>
</li>)
}</ul>
</Fragment>
);
const MenuItem = ({ item, checked, onChange }) => (
<Fragment>
<input
key={item.id}
type="checkbox"
checked={checked}
onChange={onChange} />
<span>{item.title}</span>
{item.discount && <span style={{ color: 'red' }}> [-{item.discount}%]</span>}
</Fragment>);
These Two components are what we used to call “dumb” components – they’re stateless and only rendering some UI, passing any events to their props.
useEffect
(But check the official docs for more goodies and gotachs).Hooks can really make your components lighter and much more testable, thus your app more maintainable. However you should know your way around them to make the best use of those and avoid common mistakes.