O throw w React

Czyli jak mieć ładne API bez ładnego API

@radekmie

O mnie

@radekmie

Od 2015 w Vazco.

Od 2016 z React'em na produkcji.

(Ach, LinkedStateMixin.)

Wszystko o mnie na github.com/radekmie.

Synchronicznie

export function Example() {
  throw new Error('static');

  useEffect(() => {
    throw new Error('useEffect');
  });

  useLayoutEffect(() => {
    throw new Error('useLayoutEffect');
  });

  useMemo(() => {
    throw new Error('useMemo');
  });

  useReducer(null, null, () => {
    throw new Error('useReducer initializer');
  });

  useState(() => {
    throw new Error('useState initializer');
  });

  return <div>Example</div>;
}
@radekmie

Asynchronicznie

export function Example() {
  setTimeout(() => {
    throw new Error('setTimeout');
  });

  setInterval(() => {
    throw new Error('setInterval');
  });
  
  new Promise(() => {
    throw new Error('new Promise (throw)');
  });
  
  new Promise((resolve, reject) => {
    reject(new Error('new Promise (reject)'));
  });

  Promise.reject(new Error('Promise.reject'));
  
  Promise.resolve().then(() => {
    throw new Error('Promise.then');
  });

  return <div>Example</div>;
}
@radekmie

Podczas component*

export class Example extends Component {
  constructor() { super(...arguments);
    throw new Error('constructor'); }

  componentDidCatch() {
    throw new Error('componentDidCatch'); }

  componentDidMount() {
    throw new Error('componentDidMount'); }

  componentDidUpdate() {
    throw new Error('componentDidUpdate'); }

  componentWillUnmount() {
    throw new Error('componentWillUnmount'); }

  shouldComponentUpdate() {
    throw new Error('shouldComponentUpdate'); }

  render() {
    throw new Error('render');
    // Plus wszystkie warianty asynchroniczne.

    return <div>Example</div>;
  }
}
@radekmie

Podczas on*

export function Example() {
  const onClick = () => {
    throw new Error('onClick');
    // Plus wszystkie warianty asynchroniczne...
  };

  return <div onClick={onClick}>Example</div>;
}
@radekmie

Co można złapać?

Error boundaries, czyli komponenty zawierające getDerivedStateFromError lub componentDidCatch, złapią wszystkie błędy synchroniczne.

Na wszystko inne zostaje tylko try/catch.

The above error occurred in the <Example> component: at Example Consider adding an error boundary to your tree to customize error handling behavior. Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

@radekmie

A co jeśli rzucę...

export function Example() {
  throw new Error('Error object');

  throw 20191011;

  throw 'Error message...?';

  throw null;

  throw undefined;

  throw Promise.resolve();

  return <div>Example</div>;
}

Example suspended while rendering, but no fallback UI was specified. Add a <Suspense fallback=...> component higher in the tree to provide a loading indicator or placeholder to display.

@radekmie

Suspense!?

// React Cache for simple data fetching (not final API)
import {unstable_createResource} from 'react-cache';

// Tell React Cache how to fetch your data
const TodoResource = unstable_createResource(fetchTodo);

function Todo(props) {
  // Suspends until the data is in the cache
  const todo = TodoResource.read(props.id);
  return <li>{todo.title}</li>;
}

function App() {
  return (
    // Same Suspense component you already use for code splitting
    // would be able to handle data fetching too.
    <React.Suspense fallback={<Spinner />}>
      <ul>
        {/* Siblings fetch in parallel */}
        <Todo id="1" />
        <Todo id="2" />
      </ul>
    </React.Suspense>
  );
}
@radekmie

Inne API?

// Opcja A: Asynchroniczne komponenty.
async function TodoAsync(props) {
  const todo = await read(props.id);
  return <li>{todo.title}</li>;
}

// Opcja B: Komponenty generatorowe.
function TodoGenerator*(props) {
  const todo = yield read(props.id);
  return <li>{todo.title}</li>;
}

// Opcja C: Rzucanie Promise.
function Todo(props) {
  const todo = resource.read(props.id);
  return <li>{todo.title}</li>;
}

// Opcja D: Efekty algebraiczne.
function TodoEffect(props) {
  const todo = effect read(props.id);
  return <li>{todo.title}</li>;
}
@radekmie

I co teraz?

Caution:

This page was about experimental features that aren’t yet available in a stable release. It was aimed at early adopters and people who are curious.

Much of the information on this page is now outdated and exists only for archival purposes. Please refer to the React 18 Alpha announcement post for the up-to-date information.

Before React 18 is released, we will replace this page with stable documentation.


Czyli nic.


@radekmie

TL;DR;

... mamy ograniczenia składniowe.

<Suspense> to tylko idea.

Samo API nie ma znaczenia.

(Finalnego wciąż nie ma.)

To wciąż tylko JavaScript, więc...

@radekmie

throw undefined; to zło.

Pytania?

@radekmie

O throw w React

By Radosław Miernik

O throw w React

ReactJS Wroclaw #22

  • 957