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
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Fakiolas Marios
June 24, 2019
Programming
36
0
Share
The biggest lies about React Hooks
What problems React Hooks do really solve?
Fakiolas Marios
June 24, 2019
More Decks by Fakiolas Marios
See All by Fakiolas Marios
Modern e2e testing for complex web applications with Cypress.io
fakiolinho
0
25
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
61
Other Decks in Programming
See All in Programming
初めてのRubyKaigiはこう見えた
jellyfish700
0
400
「エンジニアインターン、どうやって取った?」準備のリアルを語るLT会 Progate BAR
akiomatic
0
110
RTSPクライアントを自作してみた話
simotin13
0
420
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
130
net-httpのHTTP/2対応について
naruse
0
410
さぁV100、メモリをお食べ・・・
nilpe
0
120
LLM Plugin for Node-REDの利用方法と開発について
404background
0
150
誰も頼んでない機能を出荷した話
zekutax
0
160
CSC307 Lecture 17
javiergs
PRO
0
310
ビジネスモデルから紐解く、AI+型駆動開発
hirokiomote
2
5.1k
プロパティの順序で型推論が壊れる!? TypeScript6.0の修正からContext-Sensitivityの仕組みを追う
bicstone
2
1.3k
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
3.2k
Featured
See All Featured
Ecommerce SEO: The Keys for Success Now & Beyond - #SERPConf2024
aleyda
1
2k
Exploring anti-patterns in Rails
aemeredith
3
380
The untapped power of vector embeddings
frankvandijk
2
1.7k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
1.9k
Unlocking the hidden potential of vector embeddings in international SEO
frankvandijk
0
830
Leo the Paperboy
mayatellez
7
1.8k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
240
New Earth Scene 8
popppiees
3
2.3k
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
The Illustrated Children's Guide to Kubernetes
chrisshort
51
52k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
150
The SEO identity crisis: Don't let AI make you average
varn
0
480
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