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
57
Other Decks in Programming
See All in Programming
Best-Practices-for-Cortex-Analyst-and-AI-Agent
ryotaroikeda
1
110
そのAIレビュー、レビューしてますか? / Are you reviewing those AI reviews?
rkaga
6
4.6k
開発者から情シスまで - 多様なユーザー層に届けるAPI提供戦略 / Postman API Night Okinawa 2026 Winter
tasshi
0
200
HTTPプロトコル正しく理解していますか? 〜かわいい猫と共に学ぼう。ฅ^•ω•^ฅ ニャ〜
hekuchan
2
690
生成AIを使ったコードレビューで定性的に品質カバー
chiilog
1
270
CSC307 Lecture 04
javiergs
PRO
0
660
AIによる高速開発をどう制御するか? ガードレール設置で開発速度と品質を両立させたチームの事例
tonkotsuboy_com
7
2.4k
組織で育むオブザーバビリティ
ryota_hnk
0
180
【卒業研究】会話ログ分析によるユーザーごとの関心に応じた話題提案手法
momok47
0
200
今から始めるClaude Code超入門
448jp
8
8.9k
FOSDEM 2026: STUNMESH-go: Building P2P WireGuard Mesh Without Self-Hosted Infrastructure
tjjh89017
0
170
CSC307 Lecture 09
javiergs
PRO
1
840
Featured
See All Featured
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
170
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
2.7k
The Cost Of JavaScript in 2023
addyosmani
55
9.5k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.6k
Are puppies a ranking factor?
jonoalderson
1
2.7k
B2B Lead Gen: Tactics, Traps & Triumph
marketingsoph
0
55
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.2k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
5.8k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
430
What does AI have to do with Human Rights?
axbom
PRO
0
2k
Darren the Foodie - Storyboard
khoart
PRO
2
2.4k
Making Projects Easy
brettharned
120
6.6k
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