Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
The biggest lies about React Hooks
Search
Fakiolas Marios
June 24, 2019
Programming
0
31
The biggest lies about React Hooks
What problems React Hooks do really solve?
Fakiolas Marios
June 24, 2019
Tweet
Share
More Decks by Fakiolas Marios
See All by Fakiolas Marios
Modern e2e testing for complex web applications with Cypress.io
fakiolinho
0
23
Get rid of controllers in angular 1.5.x start using component directives
fakiolinho
0
110
Web components are the future of the web - Take advantage of new web technologies using PolymerJS
fakiolinho
0
130
Angular 2 - How we got here?
fakiolinho
0
56
Other Decks in Programming
See All in Programming
Modern Angular with Signals and Signal Store:New Rules for Your Architecture @enterJS Advanced Angular Day 2025
manfredsteyer
PRO
0
170
Benchmark
sysong
0
280
Blazing Fast UI Development with Compose Hot Reload (droidcon New York 2025)
zsmb
1
270
PostgreSQLのRow Level SecurityをPHPのORMで扱う Eloquent vs Doctrine #phpcon #track2
77web
2
420
What Spring Developers Should Know About Jakarta EE
ivargrimstad
0
360
WebViewの現在地 - SwiftUI時代のWebKit - / The Current State Of WebView
marcy731
0
110
なぜ「共通化」を考え、失敗を繰り返すのか
rinchoku
1
620
設計やレビューに悩んでいるPHPerに贈る、クリーンなオブジェクト設計の指針たち
panda_program
6
1.8k
Composerが「依存解決」のためにどんな工夫をしているか #phpcon
o0h
PRO
1
250
LT 2025-06-30: プロダクトエンジニアの役割
yamamotok
0
650
Hypervel - A Coroutine Framework for Laravel Artisans
albertcht
1
110
ペアプロ × 生成AI 現場での実践と課題について / generative-ai-in-pair-programming
codmoninc
0
210
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.4k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
31
1.3k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
26
2.9k
Unsuck your backbone
ammeep
671
58k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
248
1.3M
Reflections from 52 weeks, 52 projects
jeffersonlam
351
20k
Adopting Sorbet at Scale
ufuk
77
9.4k
Building an army of robots
kneath
306
45k
Optimizing for Happiness
mojombo
379
70k
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
34
3.1k
Transcript
The biggest lies about The biggest lies about React Hooks
React Hooks
[email protected]
twitter.com/@fakiolinho - medium.com/@fakiolinho 1
Full-stack JavaScript lover, happy husband, proud father Software Engineering Manager
/ Frontend Head at omilia.com Fakiolas Marios
[email protected]
- twitter.com/@fakiolinho - medium.com/@fakiolinho Workshops Tutor at 2hog.codes 2
React Hooks React Hooks React 16.8 - 6/2/2019 3 .
1
React Hooks React Hooks React 16.8 - 6/2/2019 3 .
2
React Hooks React Hooks were created so we can win
were created so we can win the fight against evil classes the fight against evil classes 4 . 1
React Hooks React Hooks were created so we can win
were created so we can win the fight against evil classes the fight against evil classes 4 . 2
React Hooks React Hooks so why then? 5
React Hooks React Hooks were created in order to re-use
logic without nesting deeper in the components tree ...i am looking at you HOCs and render props 6
As an architect, you are asked to design a brand
new project 7
Your go-to technology is ReactJS 8
Specs indicate that lots of forms will be implemented 9
You decide to go with controlled components 10 . 1
class Form extends React.Component { state = { field: '',
}; handleSubmit = data => axios.post('/url', data); render() { return ( <form onSubmit={this.handleSubmit}> <input value={this.state.field} onChange={e => ( this.setState({ field: e.target.value }) )} /> </form> ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 A class component is required 10 . 2
state = { field: '', }; <input value={this.state.field} onChange={e =>
( this.setState({ field: e.target.value }) )} class Form extends React.Component { 1 2 3 4 5 handleSubmit = data => axios.post('/url', data); 6 7 render() { 8 return ( 9 <form onSubmit={this.handleSubmit}> 10 11 12 13 14 15 /> 16 </form> 17 ); 18 } 19 Because you need internal state 10 . 3
...and you ship it 11
...the project should support longer forms with multiple fields 12
Who hates some old-fashioned copy-paste right? 13 . 1
<form onSubmit={this.handleSubmit}> <input value={this.state.field1} onChange={e => ( this.setState(prevState => ({
...prevState, field1: e.target.value })) )} /> <input value={this.state.field2} onChange={e => ( this.setState(prevState => ({ ...prevState, field2: e.target.value })) )} /> ... </form> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 13 . 2
...and you ship it 14
...the project should support complex forms with different types of
fields 15
Copy and paste won't do the job this time 16
maybe we can create some re-usable components and move faster
17
const Field = ({ name="field", value="", type="text", onChange, }) =>
( <input name={name} type={type} value={value} onChange={onChange} /> ); 1 2 3 4 5 6 7 8 9 10 11 12 13 Let's create our own Field component 18 . 1
class Form extends React.Component { state = { field: '',
}; handleChange = e => this.setState({ [e.target.name]: e.target.value, }); handleSubmit = e => { e.preventDefault(); axios.post('/url', this.state); }; render() { return ( <form onSubmit={this.handleSubmit}> <Field name="field" value={this.state.field} onChange={this.handleChange} /> </form> ); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 Refactor our Form component 18 . 2
handleChange = e => this.setState(prevState => ({ ...prevState, [e.target.name]: e.target.value,
})); <Field name="field" value={this.state.field} onChange={this.handleChange} /> <Field.../> class Form extends React.Component { 1 state = { 2 field: '', 3 }; 4 5 6 7 8 9 10 handleSubmit = e => ...; 11 12 render() { 13 return ( 14 <form onSubmit={this.handleSubmit}> 15 16 17 18 19 20 21 </form> 22 ); 23 } 24 } 25 Field component can be re-used easily 18 . 3
What about forms logic? It is not that re-usable 19
. 1
state = { field: '', }; handleChange = e =>
this.setState({ [e.target.name]: e.target.value, }); handleSubmit = e => { e.preventDefault(); axios.post('/url', this.state); }; class Form extends React.Component { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 render() { 15 return ( 16 <form onSubmit={this.handleSubmit}> 17 <Field 18 name="field" 19 value={this.state.field} 20 onChange={this.handleChange} 21 /> 22 </form> 23 ); 24 } 25 } 26 Repeated logic across all forms 19 . 2
Let's provide a wrapper that will bring this kind of
logic anywhere we like 20
const Form = () => { const initialValues = {
field: "", }; const handleSubmit = data => axios.post('/url', data); return ( <FormHandler initialValues={initialValues} onSubmit={handleSubmit}> {({ values, onChange, onSubmit }) => ( <form onSubmit={onSubmit}> <Field value={values.field} name="field" onChange={onChange} /> </form> )} </FormHandler> ); }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 Let's use render props pattern 21 . 1
<FormHandler initialValues={initialValues} onSubmit={handleSubmit}> {({ values, onChange, onSubmit }) => (
)} </FormHandler> const Form = () => { 1 const initialValues = { 2 field: "", 3 }; 4 5 const handleSubmit = data => axios.post('/url', data); 6 7 return ( 8 9 10 <form onSubmit={onSubmit}> 11 <Field 12 value={values.field} 13 name="field" 14 onChange={onChange} 15 /> 16 </form> 17 18 19 ); 20 }; 21 Re-usable logic by using render props 21 . 2
<form onSubmit={onSubmit}> value={values.field} onChange={onChange} const Form = () => {
1 const initialValues = { 2 field: "", 3 }; 4 5 const handleSubmit = data => axios.post('/url', data); 6 7 return ( 8 <FormHandler initialValues={initialValues} onSubmit={handleSubmit}> 9 {({ values, onChange, onSubmit }) => ( 10 11 <Field 12 13 name="field" 14 15 /> 16 </form> 17 )} 18 </FormHandler> 19 ); 20 }; 21 Re-usable logic by using render props 21 . 3
export default class FormHandler extends React.Component { state = this.props.initialValues;
handleChange = e => { e.persist(); this.setState(prevState => ({ ...prevState, [e.target.name]: e.target.value })); }; handleSubmit = e => { e.preventDefault(); this.props.onSubmit(this.state); }; render() { return this.props.children({ values: this.state, onChange: this.handleChange, onSubmit: this.handleSubmit }); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Re-usable logic by using render props 21 . 4
Neat, our forms are looking good 22
...the project needs to provide a confirmation step for all
the forms that have a destructive purpose 23
We need a confirmation step for certain forms 24 .
1
Should we add a prop named "shouldDoubleCheck" to prevent forms
submission at will? <FormHandler shouldDoubleCheck initialValues={initialValues} onSubmit={onSubmit} > ... </FormHandler> 1 2 3 4 5 6 7 24 . 2
handleSubmit = e => { e.preventDefault(); if (this.props.shouldDoubleCheckout) { const
answer = window.confirm('Are you really sure about this?'); if (answer) { this.props.onSubmit(this.state); } } else { this.props.onSubmit(this.state); } }; 1 2 3 4 5 6 7 8 9 10 11 12 13 Check for "shouldDoubleCheck" across all forms submissions 24 . 3
This logic will run across all forms right? Only a
few really will use it 25
We need another wrapper that will introduce this confirmation logic
26
<FormHandler initialValues={initialValues} onSubmit={handleSubmit}> {({ values, onChange, onSubmit }) => (
<DoubleCheckHandler onSubmit={onSubmit}> {({ onSubmitWithDoubleCheck }) => ( <form onSubmit={onSubmitWithDoubleCheck}> <Field value={values.field} name="field" label="Field" onChange={onChange} /> </form> )} </DoubleCheckHandler> )} </FormHandler> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Introduce "DoubleCheckHandler" wrapper 27 . 1
<DoubleCheckHandler onSubmit={onSubmit}> {({ onSubmitWithDoubleCheck }) => ( <form onSubmit={onSubmitWithDoubleCheck}> )}
</DoubleCheckHandler> <FormHandler initialValues={initialValues} onSubmit={handleSubmit}> 1 {({ values, onChange, onSubmit }) => ( 2 3 4 5 <Field 6 value={values.field} 7 name="field" 8 label="Field" 9 onChange={onChange} 10 /> 11 </form> 12 13 14 )} 15 </FormHandler> 16 Introduce "DoubleCheckHandler" wrapper 27 . 2
const DoubleCheckHandler = ({ onSubmit, children }) => { const
handleSubmitWithDoubleCheck = e => { e.preventDefault(); const answer = window.confirm("Are you really sure about this?"); if (answer) { onSubmit(e); } }; return children({ onSubmitWithDoubleCheck: handleSubmitWithDoubleCheck }); }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 No "shouldDoubleCheck" prop is needed in DoubleCheckHandler 27 . 3
Neat, our forms are looking good Let's share all this
effort with the teammates 28
No-one seems to be excited 29
"This is not that readable. How are we going to
maintain these components?" 30 . 1
<FormHandler initialValues={initialValues} onSubmit={handleSubmit}> {({ values, onChange, onSubmit }) => (
<DoubleCheckHandler onSubmit={onSubmit}> {({ onSubmitWithDoubleCheck }) => ( ... )} </DoubleCheckHandler> )} </FormHandler> 1 2 3 4 5 6 7 8 9 30 . 2
"What about all these wrapping components? Components tree seems pretty
ugly" 31 . 1
31 . 2
"What about testing? How deep we should go to find
and tweak a Field?" 32 . 1
We need to use full mount with enzyme or many
dives with shallow testing 32 . 2
Obviously this solution isn't that cool 33
Time to jump 1 year ahead and reach Hooks era
34 . 1
const Form = () => { const initialValues = {
field: '', }; const handleSubmit = data => axios.post('/url', data); // We need a mechanism to get: // 1. updated values // 2. re-usable onChange handler // 3. re-usable onSubmit handler return ( <form onSubmit={onSubmit}> <Field value={values.field} name="field" onChange={onChange} /> </form> ); }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Let's take 1 big breath and start from the very start 34 . 2
const { values, onChange, onSubmit, } = useForm(initialValues, handleSubmit); const
Form = () => { 1 const initialValues = { 2 field: '', 3 }; 4 5 const handleSubmit = data => axios.post('/url', data); 6 7 8 9 10 11 12 13 return ( 14 <form onSubmit={onSubmit}> 15 <Field 16 value={values.field} 17 name="field" 18 onChange={onChange} 19 /> 20 </form> 21 ); 22 }; 23 A custom Hook is all we need 34 . 3
const useForm = (initialValues = {}, onSubmit) => { const
[values, setValues] = React.useState(initialValues); const handleChange = e => { e.persist(); setValues({ ...values, [e.target.name]: e.target.value }); }; const handleSubmit = e => { e.preventDefault(); onSubmit(values); }; return { values, onChange: handleChange, onSubmit: handleSubmit }; }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 We can create a custom Hook with some internal state 34 . 4
const [values, setValues] = React.useState(initialValues); const useForm = (initialValues =
{}, onSubmit) => { 1 2 3 const handleChange = e => { 4 e.persist(); 5 setValues({ 6 ...values, 7 [e.target.name]: e.target.value 8 }); 9 }; 10 11 const handleSubmit = e => { 12 e.preventDefault(); 13 onSubmit(values); 14 }; 15 16 return { values, onChange: handleChange, onSubmit: handleSubmit }; 17 }; 18 "useState" Hook does all the dirty work 34 . 5
const Form = () => { const initialValues = {
field: '', }; const handleSubmit = data => axios.post('/url', data); const { values, onChange, onSubmit, } = useForm(initialValues, handleSubmit); return ( <form onSubmit={onSubmit}> <Field value={values.field} name="field" onChange={onChange} /> </form> ); }; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 Much more readable code with Hooks 35 . 1
const { values, onChange, onSubmit, } = useForm(initialValues, handleSubmit); const
{ onDoubleCheckSubmit } = useDoubleCheck(onSubmit); <form onSubmit={onDoubleCheckSubmit}> const Form = () => { 1 const initialValues = { 2 field: '', 3 }; 4 5 const handleSubmit = data => axios.post('/url', data); 6 7 8 9 10 11 12 13 14 return ( 15 16 <Field 17 value={values.field} 18 name="field" 19 onChange={onChange} 20 /> 21 </form> 22 ); 23 }; 24 Much more readable code with Hooks 35 . 2
Cleaner components tree with Hooks 36
No more deep dive to test elements behaviour with Hooks
37
...everyone is happy, so you ship it 38
Code re-usability with some simple functions and not complex patterns
Much more readable code No more garbage in components tree React Hooks pros React Hooks pros 39
We still need classes for a couple cases: Error Boundaries
getSnapshotBeforeUpdate we cannot use Hooks directly inside classes Do Hooks replace classes? Do Hooks replace classes? 40
Questions 41