React

Лекция 25

React

  • Оффициальный сайт
  • View библиотека от Facebook
  • Декларативная
  • Компонентно-ориентированная
  • Learn Once, Write Anywhere

React

  • Virtual DOM (Document Object Model)
  • Тестируемость
  • Переиспользование
  • Props и State
  • Чистые компоненты
  • JSX

React - Sandbox


<div id="app"></div>

<script src="https://unpkg.com/react@16.2.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.2.0/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.min.js"></script>
<script src="https://unpkg.com/babel-polyfill@6.26.0//dist/polyfill.min.js"></script>

<script type="text/babel">
  ...
</script>
      

Hello World


class App extends React.Component {
  render() {
    return (
      <div>
        Hello from React!
      </div>
    );
  }
}

ReactDOM.render(
  <App/>,
  document.getElementById('app')
);
      

Hello World


class App extends React.Component {
  render() {
    return React.createElement(
      "div",
      null,
      "Hello from React!"
    );
  }
}

ReactDOM.render(
  React.createElement(App),
  document.getElementById('app')
);
      

Hello World


class App extends React.Component {
  constructor(props) {
    super(props);

    this.click = this.click.bind(this);
  }

  render() {
    return <div onClick={this.click}>Hi</div>;
  }

  click() { console.log(this.props.title); }
}

ReactDOM.render(<App title='Next Facebook!'/>,
  document.getElementById('app'));
      

Hello World


class App extends React.Component {
  constuctor(props) {
    super(props);

    this.click = this.click.bind(this);
  }

  render() {
    return <div onClick={this.click}>Hi</div>
  },

  click() {
    console.log(this.props.title);
  }
});

ReactDOM.render(<App title='Next Facebook!'/>,
  document.getElementById('app'));
      

Virtual DOM

Virtual DOM

  • абстракция над DOM
  • приложение работает с VDOM, который после всех изменений сам рассчитывает как более оптимально сделать изменения в DOM
  • dirty cheking vs observable

Virtual DOM

  • произошло изменение
  • сделать снапшот VDOM
  • сгенерировать новый VDOM
  • вычислить дельту
  • внести изменения в DOM
  • matt-esch/virtual-dom

Virtual DOM


const h = require('virtual-dom/h');
const diff = require('virtual-dom/diff');
const patch = require('virtual-dom/patch');
const createElement = require('virtual-dom/create-element');
      

Virtual DOM


function render(count)  {
  return h('div', {
    style: {
      textAlign: 'center',
      lineHeight: (100 + count) + 'px',
      border: '1px solid red',
      width: (100 + count) + 'px',
      height: (100 + count) + 'px'
    }
  }, [String(count)]);
}
      

Virtual DOM


let count = 0;

let tree = render(count);
let rootNode = createElement(tree);
document.body.appendChild(rootNode);
      

Virtual DOM


setInterval(function () {
  count++;

  const newTree = render(count);
  const patches = diff(tree, newTree);
  rootNode = patch(rootNode, patches);
  tree = newTree;
}, 1000);
      

JSX


const element = <h1>Hello, world!</h1>;
      

JSX


function formatName(user) {
  return user.firstName + ' ' + user.lastName;
}

const user = {
  firstName: 'Harper',
  lastName: 'Perez'
};

const element = (
  <h1>
    Hello, {formatName(user)}!
  </h1>
);
      

JSX


function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello, Stranger.</h1>;
}
      

JSX


<MyComponent message={'hello world'} />
<MyComponent onClick={this._onClick} />
      

JSX


<MyContainer>
  <MyFirstComponent />
  <MySecondComponent />
</MyContainer>
      

Rendering


function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  ReactDOM.render(element, document.getElementById('root'));
}

setInterval(tick, 1000);
      

Rendering

Props & State


function Hello(props) {
  return <h1>Hello, {props.name}</h1>;
}

ReactDOM.render(
  <Hello name="Moto"/>,
  document.getElementById('app')
);
      

Props & State


class Hello extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}
      

Props & State


class Hello extends React.Component {
  constructor(props) {
    super(props);
    this.state = { names: ['Rick', 'Carl', 'Negan'],
      current: 0 };
  }

  componentDidMount() {
    setInterval(() => { this.setState({
      current: (this.state.current + 1) % 3
    })}, 1000);
  },

  render() {
    return (<div>Hello
      {this.state.names[this.state.current]}!
    </div>);
  }
});
      

TO-DO LIST


class ToDoModel {
  constructor() {
    this.list = [];
  }

  getItems() {
    return this.list;
  }

  getActiveItems() {
    return this.list.filter(x => !x.completed);
  }

  getCompletedItems() {
    return this.list.filter(x => x.completed);
  }

  ...
}
      

class ToDoModel {
  ...

  getActiveCount() {
    return this.list
        .filter(x => !x.completed)
        .length;
  }

  getCompletedCount() {
    return this.list
        .filter(x => x.completed)
        .length;
  }

  ...
}
      

class ToDoModel {
  ...

  addItem(text) {
    let item = {
      id: Date.now() + this.list.length,
      text: text,
      completed: false
    };

    this.list.push(item);

    return item;
  }

  ...
}
      

class ToDoModel {
  ...

  removeItem(id) {
    let index = this.list
      .findIndex(x => x.id === id);

    this.list.splice(index, 1);
  }

  removeCompleted() {
    this.list = this.getActiveItems();
  }

  ...
}
      

class ToDoModel {
  ...

  updateItem(id, text) {
    let index = this.list
      .findIndex(x => x.id === id);

    this.list[index].text = text;
  }

  toggleItem(id) {
    let index = this.list
      .findIndex(x => x.id === id);

    this.list[index].completed
      = !this.list[index].completed;
  }

  ...
}
      

class ToDoModel {
  ...

  switchAllTo(completed) {
    this.list
      .forEach(x => x.completed = completed);
  }
}
      

class NavModel {
  constructor() {
    this.links = [
      { title: 'All' },
      { title: 'Active' },
      { title: 'Completed' }
    ];

    this.active = this.links[0];
  }

  ...
}
      

class NavModel {
  ...

  getLinks() {
    return this.links;
  }

  getActive() {
    return this.active;
  }

  setActive(link) {
    this.active = link;
  }
}
      

class ToDo extends React.Component {
  constructor(props) {
    super(props);

    this._rerender = this._rerender.bind(this);
    this._toggleItem = this._toggleItem.bind(this);
    this._toogleAll = this._toogleAll.bind(this);
    this._removeItem = this._removeItem.bind(this);
    this._addItem = this._addItem.bind(this);
    this._updateItem = this._updateItem.bind(this);
    this._removeCompleted = this._removeCompleted.bind(this);
    this._navigate = this._navigate.bind(this);

    this.state = this._getState();
  }
  ...
});
      

class ToDo extends React.Component {
  ...
  render() {
    return (
      <div className="todo">
        ...
      </div>
    );
  }
  ...
});
      

<div className="todo">
  <div className="todo__title">React ToDo</div>
  <Nav links={this.state.links}
      activeLink={this.state.activeLink}
      navigate={this._navigate}/>
  <ToDoSummary remains={this.state.remains}
      completed={this.state.completed}/>
  <ToDoList tasks={this.state.tasks}
      areAllComplete={this.state.areAllCompleted}
      toggleItem={this._toggleItem}
      toggleAll={this._toogleAll}
      removeItem={this._removeItem}
      updateItem={this._updateItem}
  />
  <ToDoForm addItem={this._addItem}/>
  <ToDoClear
      removeCompleted={this._removeCompleted}/>
</div>
      

class ToDo extends React.Component {
  ...
  _rerender() {
    this.setState(this._getState());
  }
  ...
});
      

class ToDo extends React.Component {
  ...
  _getState() {
    const state = {
      remains: todoModel.getActiveCount(),
      completed: todoModel.getCompletedCount(),

      links: navModel.getLinks(),
      activeLink: navModel.getActive()
    };

    state.areAllCompleted = state.remains === 0;
    ...
  }
  ...
});
      

class ToDo extends React.Component {
  ...
  _getState() {
    ...
    if (state.activeLink.title === 'All') {
      state.tasks = todoModel.getItems();
    } else if (state.activeLink.title === 'Completed') {
      state.tasks = todoModel.getCompletedItems();
    } else {
      state.tasks = todoModel.getActiveItems();
    }

    return state;
  }
  ...
});
      

class ToDo extends React.Component {
  ...
  _toggleItem(id) {
    todoModel.toggleItem(id);
    this._rerender();
  }

  _toogleAll() {
    todoModel.switchAllTo(!this.state.areAllCompleted);
    this._rerender();
  }

  _removeItem(id) {
    todoModel.removeItem(id);
    this._rerender();
  }
  ...
});
      

class ToDo extends React.Component {
  ...
  _addItem(text) {
    todoModel.addItem(text);
    this._rerender();
  }

  _updateItem(id, text) {
    todoModel.updateItem(id, text);
    this._rerender();
  }
  ...
});
      

class ToDo extends React.Component {
  ...
  _removeCompleted() {
    todoModel.removeCompleted();
    this._rerender();
  }

  _navigate(link) {
    navModel.setActive(link);
    this._rerender();
  }
});
      

class Nav extends React.Component {
  render() {
    const items = this.props.links.map((link) => {
      return (
        <NavItem key={link.title}
            link={link}
            navigate={this.props.navigate}
            isActive={link.title
                === this.props.activeLink.title}
        />
      )
    });

    return (
        <div className="nav">
          {items}
        </div>
    );
  }
});
      

class NavItem extends React.Component {
  constructor(props) {
    super(props);

    this._navigate = this._navigate.bind(this);
  }
  ...
});
      

class NavItem extends React.Component {
  ...
  render() {
    return (
      <div className={'nav__item'
          + (this.props.isActive
            ? ' nav__item_active' : '')}
          onClick={this._navigate}>

        {this.props.link.title}

      </div>
    );
  },

  _navigate() {
    this.props.navigate(this.props.link)
  }
});
      

class ToDoSummary extends React.Component {
  render() {
    return (
      <div className="todo-info">
        <span className="todo-info__remains">
          {this.props.remains} remains
        </span>
        {' '}
        <span className="todo-info__completed">
          / {this.props.completed} completed
        </span>
      </div>
    );
  }
});
      

class ToDoList extends React.Component {
  render() {
    const items = this.props.tasks.map((task) => {
      return (
        <ToDoItem key={task.id}
            task={task}
            toggleItem={this.props.toggleItem}
            removeItem={this.props.removeItem}
            updateItem={this.props.updateItem}
        />
      );
    });
    ...
  }
});
      

class ToDoList extends React.Component {
  render() {
    ...
    return (
      <div className="todo__list">
        <div className="todo__toggle-all">
          <input type="checkbox"
              className="todo__checkbox"
              checked={this.props.areAllComplete}
              onChange={this.props.toggleAll}/>
          {' '}
          Complete all
        </div>

        {items}
      </div>
    );
  }
});
      

class ToDoItem extends React.Component {
  constructor(props) {
    super(props);

    this._edit = this._edit.bind(this);
    this._save = this._save.bind(this);
    this._toggleItem = this._toggleItem.bind(this);
    this._removeItem = this._removeItem.bind(this);

    this.state = {
      isEditing: false
    };
  }
  ...
});
      

class ToDoItem extends React.Component {
  ...
  _edit() {
    this.setState({ isEditing: true });
  }

  _save(text) {
    this.setState({ isEditing: false });
    this.props.updateItem(
      this.props.task.id,
      text
    );
  }
  ...
});
      

class ToDoItem extends React.Component {
  ...
  _toggleItem() {
    this.props.toggleItem(this.props.task.id);
  }

  _removeItem() {
    this.props.removeItem(this.props.task.id);
  }
  ...
});
      

class ToDoItem extends React.Component {
  ...
  render() {
    const text = this.state.isEditing ? (
      <ToDoTextInput
        className="todo__text todo__text_editing"
        text={this.props.task.text}
        onSave={this._save}/>
      )
      : (<span className={'todo__text'
            + (this.props.task.completed
            ? ' todo__text_completed' : '')}
          onDoubleClick={this._edit}>
          {this.props.task.text}
        </span>
      );
      ...
    );
  }
});
      

class ToDoItem extends React.Component {
  ...
  render() {
    ...
    return (
      <div className="todo__item">
        <input type="checkbox"
          className="todo__checkbox"
          checked={this.props.task.completed}
          onChange={this._toggleItem}/>
        <span className="todo__destroy"
          onClick={this._removeItem}>-</span>
        {' '}
        {text}
      </div>
    );
  }
});
      

class ToDoForm extends React.Component {
  constructor(props) {
    super(props);

    this._save = this._save.bind(this);
  }
  ...
});
      

class ToDoForm extends React.Component {
  ...
  render() {
    return (
      <div className="todo__form">
        <ToDoTextInput
            className="todo__text-input"
            placeholder="I need to do..."
            onSave={this._save}
        />
      </div>
    );
  },

  _save(text) {
    this.props.addItem(text);
  }
});
      

class ToDoTextInput extends React.Component {
  constructor(props) {
    super(props);

    this._save = this._save.bind(this);
    this._onChange = this._onChange.bind(this);
    this._onKeyDown = this._onKeyDown.bind(this);

    this.state = {
      text: this.props.text ? this.props.text : ''
    };
  }
  ...
});
      

class ToDoTextInput extends React.Component {
  ...
  _save: function() {
    this.props.onSave(this.state.text);
    this.setState({ text: '' });
  }
  ...
});
      

class ToDoTextInput extends React.Component {
  ...
  _onChange: function(event) {
    this.setState({
      text: event.target.value
    });
  }

  _onKeyDown: function(event) {
    if (event.keyCode !== 13) return;

    this._save();
  }
  ...
});
      

class ToDoTextInput extends React.Component {
  ...
  render() {
    return (
      <input className={this.props.className}
        placeholder={this.props.placeholder}
        value={this.state.text}
        onChange={this._onChange}
        onKeyDown={this._onKeyDown}/>
    );
  }
});
      

class ToDoClear extends React.Component {
  render() {
    return (
      <div className="todo__clear"
           onClick={this.props.removeCompleted}>
        Clear
      </div>
    );
  }
});
      

let sleep = todoModel.addItem('Sleep');
todoModel.addItem('Eat');
todoModel.addItem('Code');
todoModel.addItem('Repeat');

todoModel.toggleItem(sleep.id);

ReactDOM.render(
  <ToDo/>,
  document.getElementById('app')
);
      

More React

Lifecycle - Mounting


constructor(props)
      

getDerivedStateFromProps(nextProps, prevState)
componentWillMount() // legacy
      

render()
      

componentDidMount()
      

Lifecycle - Updating


getDerivedStateFromProps(nextProps, prevState)
componentWillReceiveProps(nextProps) // legacy
      

shouldComponentUpdate(nextProps, nextState)
      

componentWillUpdate(nextProps, nextState) // legacy
      

render()
      

Lifecycle - Updating


getSnapshotBeforeUpdate(prevProps, prevState)
      

componentDidUpdate()
      

Lifecycle - Unmounting


componentWillUnmount()
      

Pure Components


const App = function (props) {
  return <div>{props.title}</div>;
};

ReactDOM.render(
  <App title="Next Facebook"/>,
  document.getElementById('app')
);
      

Conditional Rendering


function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}
      

Conditional Rendering


function Greeting(props) {
  if (props.isLoggedIn) {
    return <UserGreeting />;
  }

  return <GuestGreeting />;
}

ReactDOM.render(
  <Greeting isLoggedIn={false} />,
  document.getElementById('root')
);
      

Conditional Rendering


function Mailbox(props) {
  return (<div>
    <h1>Hello!</h1>
    {props.unreadMessages.length > 0 &&
      <h2>
        You have {unreadMessages.length}
          unread messages.
      </h2>
    }
  </div>);
}

ReactDOM.render(
  <Mailbox unreadMessages={['Hi', 'Re: Hi']} />,
  document.getElementById('root')
);
      

Conditional Rendering


render() {
  const isLoggedIn = this.state.isLoggedIn;

  return (
    <div>
      The user is
      <b>{isLoggedIn ? 'currently' : 'not'}</b>
      logged in.
    </div>
  );
}
      

Conditional Rendering


render() {
  const isLoggedIn = this.state.isLoggedIn;

  return (
    <div>
      {isLoggedIn ? (
        <LogoutButton onClick={this.logout} />
      ) : (
        <LoginButton onClick={this.login} />
      )}
    </div>
  );
}
      

Conditional Rendering


function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return (
    <div className="warning">
      Warning!
    </div>
  );
}
      

Conditional Rendering


class Page extends React.Component {
  render() {
    return (
      <div>
        <WarningBanner
          warn={this.state.showWarning}
        />

        ...
      </div>
    );
  }
}
      

Composition


function SplitPane(props) {
  return (<div className="SplitPane">
    <div className="SplitPane-left">
      {props.left}
    </div>
    <div className="SplitPane-right">
      {props.right}
    </div>
  </div>);
}

function App() {
  return (
    <SplitPane
      left={<Contacts/>} right={<Chat/>} />
  );
}
      

Higher-Order Components


const CommentListWithSubscription =
  withSubscription(
    CommentList,
    (DataSource) => DataSource.getComments()
  );

const BlogPostWithSubscription =
  withSubscription(
    BlogPost,
    (DataSource, props) =>
      DataSource.getBlogPost(props.id)
  });
      

Higher-Order Components


function withSubscription(WrappedComponent,
      selectData) {

  return class {
    ...
  };

}
      

Higher-Order Components


constructor(props) {
  super(props);

  this.handleChange = this.handleChange.bind(this);

  this.state = {
    data: selectData(DataSource, props)
  };
}

componentDidMount() {
  DataSource
    .addChangeListener(this.handleChange);
}

componentWillUnmount() {
  DataSource
    .removeChangeListener(this.handleChange);
}
      

Higher-Order Components


handleChange() {
  this.setState({
    data: selectData(DataSource, this.props)
  });
}

render() {
  return <WrappedComponent
    data={this.state.data}
    {...this.props}
  />;
}
      

Controlled Components


class NameForm extends React.Component {
  constructor(props) {
    super(props);

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);

    this.state = {value: ''};
  }
  ...
}
      

Controlled Components


class NameForm extends React.Component {
  ...
  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert(
      'A name was submitted: '
      + this.state.value
    );
    event.preventDefault();
  }
  ...
}
      

Controlled Components


class NameForm extends React.Component {
  ...
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            value={this.state.value}
            onChange={this.handleChange}
          />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}
      

Uncontrolled Components


class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.handleSubmit = this.handleSubmit.bind(this);
    this.nameRef = React.createRef();
  }
  ...
}
      

Uncontrolled Components


class NameForm extends React.Component {
  ...
  handleSubmit(event) {
    alert(
      'A name was submitted: '
      + this.nameRef.current.value
    );
    event.preventDefault();
  }
  ...
}
      

Uncontrolled Components


class NameForm extends React.Component {
  ...
  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            ref={this.nameRef}
          />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
  ...
}
      

Uncontrolled Components - Forwarding


const FancyButton = React.forwardRef(
  (props, ref) => (
    <button ref={ref} className="FancyButton">
      {props.children}
    </button>
  )
);

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

Performance


class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = { l: 0, r: 0}
  }

  render() {
    return [
      <C title="left" value={this.state.l} />,
      <C title="right" value={this.state.r} />,
    ]
  }
  ...
}
      

Performance


class App extends React.Component {
  ...
  componentDidMount() {
    setInterval(() => {
      const state = { ...this.state };

      if ((state.l + state.r) % 2 === 0) {
        state.l++;
      } else {
        state.r++;
      }

      this.setState(state);
    }, 1000);
  }
}
      

Performance - Functional Component


const C = props => {
  console.log('Rendering C', props);

  return (
    <div>
      {props.title}: {props.value}
    </div>
  );
}
      

Performance - Should Update


class C extends React.Component {
  shouldComponentUpdate(nextProps) {
    return nextProps.value !== this.props.value;
  }

  render() {
    console.log("Rendering C", this.props);

    return (
      <div>
        {this.props.title}: {this.props.value}
      </div>
    );
  }
}
      

Performance - Pure Component


class C extends React.PureComponent {
  render() {
    console.log("Rendering C", this.props);

    return (
      <div>
        {this.props.title}: {this.props.value}
      </div>
    );
  }
}
      

Performance - Pure Component Failed


class App extends React.Component {
  constructor(props) {
    super(props);

    this.state = { values: [] };
  }

  render() {
    return <C values={this.state.values} />;
  }
  ...
}
      

Performance - Pure Component Failed


class App extends React.Component {
  ...
  componentDidMount() {
    setInterval(() => {
      const state = { ...this.state };

      state.values.push(state.values.length);

      this.setState(state);
    }, 1000);
  }
}
      

Performance - Pure Component Failed


class C extends React.PureComponent {
  render() {
    console.log("Rendering C", this.props);

    return (
      <div>
        {this.props.values.join(',')}
      </div>
    );
  }
}
      

Performance - Memo


// same as PureComponent
const MyComponent = React.memo(function MyComponent(props) {
  /* render using props */
});
      

Performance - Keys


<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

>>>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

>>> 2 изменения, 1 создание
      

Performance - Keys


<ul>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

>>>

<ul>
  <li key="2014">Connecticut</li>
  <li key="2015">Duke</li>
  <li key="2016">Villanova</li>
</ul>

>>> 1 создание
      

Fragments


class Columns extends React.Component {
  render() {
    return (
      <React.Fragment>
        <td>Hello</td>
        <td>World</td>
      </React.Fragment>
    );
  }
}
      

Fragments


class Columns extends React.Component {
  render() {
    return (
      <>
        <td>Hello</td>
        <td>World</td>
      </>
    );
  }
}
      

Portals


render() {
  // React does *not* create a new div.
  // It renders the children into `domNode`.
  // `domNode` is any valid DOM node,
  // regardless of its location in the DOM.
  return ReactDOM.createPortal(
    this.props.children,
    domNode,
  );
}
      

Error Boundaries


class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false };
  }
  ...
}
      

Error Boundaries


class ErrorBoundary extends React.Component {
  ...
  componentDidCatch(error, info) {
    // Display fallback UI
    this.setState({ hasError: true });

    // You can also log the error
    // to an error reporting service
    logErrorToMyService(error, info);
  }
  ...
}
      

Error Boundaries


class ErrorBoundary extends React.Component {
  ...
  render() {
    if (this.state.hasError) {
      // You can render any custom fallback UI
      return <h1>Something went wrong.</h1>;
    }
    return this.props.children;
  }
}
      

Async Set State


class App extends React.Component {
  constructor(props) {
    super(props);

    this.__onClick = this.__onClick.bind(this);

    this.state = { value: 0 };
  }
  ...
}
      

Async Set State


class App extends React.Component {
  ...
  render() {
    return (
      <div onClick={this.__onClick}>
        {this.state.value}
      </div>
    );
  }

  __onClick() {
    this.setState({ value: this.state.value + 1 });
    this.setState({ value: this.state.value + 1 });
  }
}
      

Async Set State


class App extends React.Component {
  ...
  __onClick() {
    this.setState(state =>
      ({ value: state.value + 1 })
    );

    this.setState(state =>
      ({ value: state.value + 1 })
    );
  }
}
      

Fiber

Fiber

Time Slicing

  • приоритеты для задач
  • пре-рендеринг во время простоя

Suspense