Slide 1

Slide 1 text

The New React Lifecycles @raphamorims

Slide 2

Slide 2 text

Hi, I’m Raphael アモリム

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

Slide 5

Slide 5 text

• Official Context API • createRef API • forwardRef API • Component Lifecycle Changes What’s New?

Slide 6

Slide 6 text

• Official Context API • createRef API • forwardRef API • Component Lifecycle Changes What’s New?

Slide 7

Slide 7 text

• Official Context API • createRef API • forwardRef API • Component Lifecycle Changes What’s New?

Slide 8

Slide 8 text

• Official Context API • createRef API • forwardRef API • Component Lifecycle Changes What’s New?

Slide 9

Slide 9 text

• Official Context API • createRef API • forwardRef API • Component Lifecycle Changes • Strict Mode What’s New?

Slide 10

Slide 10 text

• Official Context API • createRef API • forwardRef API • Component Lifecycle Changes • Strict Mode • React Hooks What’s New?

Slide 11

Slide 11 text

New context API const ThemeContext = React.createContext('light');

Slide 12

Slide 12 text

New context API const ThemeContext = React.createContext('light'); class ThemeProvider extends React.Component { state = {theme: 'light'}; render() { return ( {this.props.children} ); } }

Slide 13

Slide 13 text

New context API class ThemedButton extends React.Component { render() { return ( {theme => } ); } }

Slide 14

Slide 14 text

createRef class InputComponent extends Component { constructor(props) { super(props); this.inputRef = React.createRef(); } componentDidMount() { this.inputRef.current.focus(); } render() { return ; } }

Slide 15

Slide 15 text

Callback refs will continue to be supported in addition to the new createRef API. You don’t need to replace callback refs in your components.

Slide 16

Slide 16 text

const FancyButton = React.forwardRef((props, ref) => ( {props.children} )); // You can now get a ref directly to the DOM button: const ref = React.createRef(); Click me!; fowardRef

Slide 17

Slide 17 text

import React from 'react'; function Application() { return (
); } StrictMode * StrictMode is a tool for highlighting potential problems in an application. Like Fragment, StrictMode does not render any visible UI. 
 It activates additional checks and warnings for its descendants.

Slide 18

Slide 18 text

• Identifying components with unsafe lifecycles • Warning about legacy string ref API usage • Warning about deprecated findDOMNode usage • Detecting unexpected side effects • Detecting legacy context API StrictMode

Slide 19

Slide 19 text

StrictMode

Slide 20

Slide 20 text

StrictMode You probably are like this:

Slide 21

Slide 21 text

StrictMode No one likes a lint error, but it is useful.

Slide 22

Slide 22 text

New and the Old React Lifecycles

Slide 23

Slide 23 text

Legacy lifecycles will continue to work until version 17. New and the Old React Lifecycles

Slide 24

Slide 24 text

• componentWillMount • componentWillReceiveProps • componentWillUpdate Deprecated now and will be removed in React 17

Slide 25

Slide 25 text

• UNSAFE_componentWillMount • UNSAFE_componentWillReceiveProps • UNSAFE_componentWillUpdate Works on React 17 * Works with some bugs

Slide 26

Slide 26 text

• getDerivedStateFromProps • getSnapshotBeforeUpdate New lifecycles

Slide 27

Slide 27 text

getDerivedStateFromProps

Slide 28

Slide 28 text

getDerivedStateFromProps // Before class ExampleComponent extends React.Component { state = { isScrollingDown: false, }; componentWillReceiveProps(nextProps) { if (this.props.currentRow !== nextProps.currentRow) { this.setState({ isScrollingDown: nextProps.currentRow > this.props.currentRow, }); } } }

Slide 29

Slide 29 text

// After class ExampleComponent extends React.Component { // Initialize state in constructor, // Or with a property initializer. state = { isScrollingDown: false, lastRow: null, }; static getDerivedStateFromProps(props, state) { if (props.currentRow !== state.lastRow) { return { isScrollingDown: props.currentRow > state.lastRow, lastRow: props.currentRow, }; } // Return null to indicate no change to state. return null; } }

Slide 30

Slide 30 text

getSnapshotBeforeUpdate

Slide 31

Slide 31 text

// Before class ScrollingList extends Component { listRef = null; previousScrollOffset = null; componentWillUpdate(nextProps, nextState) { // Are we adding new items to the list? // Capture the scroll position so we can adjust scroll later. if (this.props.list.length < nextProps.list.length) { this.previousScrollOffset = this.listRef.scrollHeight - this.listRef.scrollTop; } } componentDidUpdate(prevProps, prevState) { // If previousScrollOffset is set, we've just added new items. // Adjust scroll so these new items don't push the old ones out of view. if (this.previousScrollOffset !== null) { this.listRef.scrollTop = this.listRef.scrollHeight - this.previousScrollOffset; this.previousScrollOffset = null; } } ...

Slide 32

Slide 32 text

class ScrollingList extends Component { listRef = null; getSnapshotBeforeUpdate(prevProps, prevState) { // Are we adding new items to the list? // Capture the scroll position so we can adjust scroll later. if (prevProps.list.length < this.props.list.length) { return ( this.listRef.scrollHeight - this.listRef.scrollTop ); } return null; } componentDidUpdate(prevProps, prevState, snapshot) { // If we have a snapshot value, we've just added new items. // Adjust scroll so these new items don't push the old ones out of view. // (snapshot here is the value returned from getSnapshotBeforeUpdate) if (snapshot !== null) { this.listRef.scrollTop = this.listRef.scrollHeight - snapshot; } } ...

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

reactjs.org/blog/2018/03/27/update-on-async-rendering.html Further Reading

Slide 35

Slide 35 text

migrating it.

Slide 36

Slide 36 text

github.com/facebook/jscodeshift

Slide 37

Slide 37 text

github.com/reactjs/react-codemod

Slide 38

Slide 38 text

$ jscodeshift -t ./unsafe-mod.js ./src --parser=flow -t

Slide 39

Slide 39 text

$ jscodeshift -t ./unsafe-mod.js ./src --parser=flow files or directory to transform -t

Slide 40

Slide 40 text

$ jscodeshift -t ./unsafe-mod.js ./src --parser=flow files or directory to transform -t

Slide 41

Slide 41 text

- "enzyme": "^3.3.0", - "enzyme-adapter-react-16": “^1.1.1” - "react-test-renderer": "^16.2.0", + "enzyme": "^3.6.0", + "enzyme-adapter-react-16": “^1.5.0", + "react-test-renderer": “^16.5.1",

Slide 42

Slide 42 text

- wrapper.instance().componentWillMount(); + wrapper.instance().UNSAFE_componentWillMount();

Slide 43

Slide 43 text

Hooks

Slide 44

Slide 44 text

No content

Slide 45

Slide 45 text

https://reactjs.org/docs/ hooks-intro.html

Slide 46

Slide 46 text

Hooks import { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [count, setCount] = useState(0); return (

You clicked {count} times

setCount(count + 1)}> Click me
); }

Slide 47

Slide 47 text

Looks like Recompose. Feels like Recompose.

Slide 48

Slide 48 text

import { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`; }); return (

You clicked {count} times

setCount(count + 1)}> Click me
); }

Slide 49

Slide 49 text

class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } componentDidMount() { document.title = `You clicked ${this.state.count} times`; } componentDidUpdate() { document.title = `You clicked ${this.state.count} times`; } render() { return (

You clicked {this.state.count} times

this.setState({ count: this.state.count + 1 })}> Click me
); } }

Slide 50

Slide 50 text

Cleanup

Slide 51

Slide 51 text

class FriendStatus extends React.Component { constructor(props) { super(props); this.state = { isOnline: null }; this.handleStatusChange = this.handleStatusChange.bind(this); } componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); } handleStatusChange(status) { this.setState({ isOnline: status.isOnline }); } render() {

Slide 52

Slide 52 text

import { useState, useEffect } from 'react'; function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); function handleStatusChange(status) { setIsOnline(status.isOnline); } useEffect(() => { ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); // Specify how to clean up after this effect: return function cleanup() { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; }

Slide 53

Slide 53 text

Cleanup

Slide 54

Slide 54 text

// Create a Context const NumberContext = React.createContext(); // It returns an object with 2 values: // { Provider, Consumer } const context = useContext(Context);

Slide 55

Slide 55 text

Basic Hooks useState useEffect useContext Additional Hooks useReducer useCallback useMemo useRef useImperativeMethods useMutationEffect useLayoutEffect

Slide 56

Slide 56 text

https:// reactjs.org/blog/2018/03/29/ react-v-16-3.html

Slide 57

Slide 57 text

https://reactjs.org/docs/ hooks-reference.html