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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
57
Other Decks in Programming
See All in Programming
AIによる開発の民主化を支える コンテキスト管理のこれまでとこれから
mulyu
3
300
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
580
AI Schema Enrichment for your Oracle AI Database
thatjeffsmith
0
290
今から始めるClaude Code超入門
448jp
8
8.8k
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
620
React 19でつくる「気持ちいいUI」- 楽観的UIのすすめ
himorishige
11
7.4k
OCaml 5でモダンな並列プログラミングを Enjoyしよう!
haochenx
0
140
AI巻き込み型コードレビューのススメ
nealle
2
300
CSC307 Lecture 09
javiergs
PRO
1
840
なぜSQLはAIぽく見えるのか/why does SQL look AI like
florets1
0
460
Data-Centric Kaggle
isax1015
2
780
IFSによる形状設計/デモシーンの魅力 @ 慶應大学SFC
gam0022
1
300
Featured
See All Featured
The Language of Interfaces
destraynor
162
26k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
9.9k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.3k
The Cult of Friendly URLs
andyhume
79
6.8k
The agentic SEO stack - context over prompts
schlessera
0
640
How to Ace a Technical Interview
jacobian
281
24k
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
1
100
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
250
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
0
140
Six Lessons from altMBA
skipperchong
29
4.1k
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
94
Design in an AI World
tapps
0
140
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