React

16.3 - 16.7(alpha)

  • Rodrigo Araújo (@dygufa)
  • Thiago Armede (@thiagoarmede)
  • (bônus) Victor Magalhães (@vhfmag)

Contexto

(não a API de contexto, contexto mesmo, tipo contextualizar)

React 16.0, Fiber, async rendering

(Stack reconciliation — é preciso terminar a atualização antes de retornar para a main thread (crédito: Lin Clark))

(Fiber reconciliation — as atualizações serão feitas em pedaços (crédito: Lin Clark))

React 16.3

Context API

const ThemeContext = React.createContext("light");
class ThemeProvider extends React.Component {
state = { theme: "light" };
render() {
return (
<ThemeContext.Provider value={this.state.theme}>
{this.props.children}
</ThemeContext.Provider>
);
}
}
class ThemedButton extends React.Component {
render() {
return (
<ThemeContext.Consumer>
{theme => <Button theme={theme} />}
</ThemeContext.Consumer>
);
}
}
function App() {
return (
<ThemeProvider>
<ThemedButton>Clica aqui</ThemedButton>
</ThemeProvider>
);
}

 

createRef

import React from "react";
// callback refs
class CallbackRefApp extends React.Component {
input = null;
state = {};
componentDidMount() {
if (this.input) {
this.input.focus();
}
}
render() {
return (
<form>
<label>Digite seu nome de usuário</label>
<input
ref={ref => (this.input = ref)}
value={this.state.username}
onChange={ev =>
this.setState({ username: ev.target.value })
}
/>
</form>
);
}
}
// createRef
class CreateRefApp extends React.Component {
inputRef = React.createRef();
state = {};
componentDidMount() {
if (this.inputRef.current) {
this.inputRef.current.focus();
}
}
render() {
return (
<form>
<label>Digite seu nome de usuário</label>
<input
ref={this.inputRef}
value={this.state.username}
onChange={ev =>
this.setState({ username: ev.target.value })
}
/>
</form>
);
}
}

 

forwardRef

import React from "react";
const FancyInput = React.forwardRef((props, ref) => (
<input {...props} ref={ref} className="fancy-input" />
));
class App extends React.Component {
inputRef = React.createRef();
state = {};
componentDidMount() {
if (this.inputRef.current) {
this.inputRef.current.focus();
}
}
render() {
return (
<form>
<label>Digite seu nome de usuário</label>
<FancyInput
ref={this.inputRef}
value={this.state.username}
onChange={ev =>
this.setState({ username: ev.target.value })
}
/>
</form>
);
}
}

 

Novos lifecycles

🙅 UNSAFE_componentWillReceiveProps 🙅
🙅 UNSAFE_componentWillUpdate 🙅
🙅 UNSAFE_componentWillMount 🙅
😍 getDerivedStateFromProps 😍
😍 getSnapshotBeforeUpdate 😍

getDerivedStateFromProps

class EmailInput extends Component {
state = {
email: this.props.defaultEmail,
prevPropsUserID: this.props.userID
};
static getDerivedStateFromProps(props, state) {
if (props.userID !== state.prevPropsUserID) {
return {
prevPropsUserID: props.userID,
email: props.defaultEmail
};
}
return null;
}
// ...
}

getSnapshotBeforeUpdate

class ScrollingList extends React.Component {
constructor(props) {
super(props);
this.listRef = React.createRef();
}
getSnapshotBeforeUpdate(prevProps, prevState) {
if (prevProps.list.length < this.props.list.length) {
const list = this.listRef.current;
return list.scrollHeight - list.scrollTop;
}
return null;
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (snapshot !== null) {
const list = this.listRef.current;
list.scrollTop = list.scrollHeight - snapshot;
}
}
render() {
return (
<div ref={this.listRef}>{/* ...contents... */}</div>
);
}
}

StrictMode

Componente que não renderiza nada e ativa alertas de uso de features que estão ou serão depreciadas

const App = () => <StrictMode>{/* resto do app */}</StrictMode>;

React 16.4

Pointer Events

"Bugfix" para getDerivedStateFromProps

React 16.5

Profiler

React 16.6

React.memo

class MyComponent extends React.PureComponent {
render() {
/* only rerenders if props change */
}
}
const MyComponent = React.memo(function MyComponent(props) {
/* only rerenders if props change */
});

Como é em classes

```notes Class components can bail out from rendering when their input props are the same using PureComponent or shouldComponentUpdate. Now you can do the same with function components by wrapping them in React.memo. ```

Code-Splitting Suspense

import React, { lazy, Suspense } from 'react';
const OtherComponent = lazy(() => import('./OtherComponent'));
function MyComponent() {
return (
<Suspense fallback={<div>Loading...</div>}>
<OtherComponent />
</Suspense>
);
}

ContextType

const MyContext = React.createContext();
class MyClass extends React.Component {
static contextType = MyContext;
componentDidMount() {
let value = this.context;
}
render() {
let value = this.context;
}
}

 

React 16.7 (alpha)

Hooks

Loving Hooks

Os Problemas

  • Classes (tem que acabar)

  • Reuso de lógica de estado

  • Rios de lifecycle methods

A Solução

import { useState } from 'react';
function Maravilhoso() {
const [count, setCount] = useState(0);
return (
<div>
<p>Hooks are {count} times cooler than classes.</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}

Maravilhas extras

😍 Nada vai quebrar 😍

😍 Menos verbosidade (bonus: transpilação) 😍

😍 Facilidade de compartilhar lógica entre componentes 😍

Principais Hooks

  • useState
  • useEffect
  • useContext

useEffect

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);
return function cleanup() {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}

 

useContext

const NumberContext = React.createContext();
function App() {
return (
<NumberContext.Provider value={42}>
<div>
<Display />
</div>
</NumberContext.Provider>
);
}
function Display() {
const value = useContext(NumberContext);
return <div>The answer is {value}.</div>;
}

 

Hooks adicionais

  • useReducer
  • useCallback
  • useRef
  • useMemo
  • useImperativeMethods
  • useLayoutEffects
  • useMutationEffects

Custom Hooks

Render props && HOCs vs Hooks

Exemplinho

Concurrent React

  • Time slicing
  • Suspense

Time-slicing

  • Usa divisão de trabalho do React Fiber para não bloquear a main thread
  • Dá diferentes prioridades para diferentes atualizações (atualizações envolvendo input são priorizadas)
  • Bônus: React vai usar propriedade hidden do HTML5 para despriorizar renderização de parte da árvore

Time-slicing

Demo

Suspense

API para lidar facilmente com chamadas assíncronas

  • Suspende renderização se dados não estão disponíveis em cache
  • Exibe fallback depois de timeout
  • Continua renderização quando chamadas assíncronas são concluídas

Suspense

Demo

Cabou

Cabou