Ответы пользователя по тегу React
  • Ошибка props is not defined?

    askhat
    @askhat
    SDE @ Akvelon
    Пропсы поступают в аргументы конструктору и рендер функции (ещё в хуки, но сейчас не об этом). В вашем случае можно определить аргумент props для метода render, а лучше просто написать this.props
    Ответ написан
  • Правильность использования функции JS?

    askhat
    @askhat
    SDE @ Akvelon
    Действительно, примеры кода эквивалентны (если не брать в расчёт то, что число 35 должно быть вторым аргументом функции bind, вероятно вы опечатались).

    Я не возьмусь говорить о том какой способ лучше, но сам чаще использую и вижу в чужом коде стрелочные функции.
    Ответ написан
  • Какой подход лучше?

    askhat
    @askhat
    SDE @ Akvelon
    Вот такой

    import React, { Component } from 'react';
    
    class App extends Component {
      render() {
        return <>...</>
      }
    }
    Ответ написан
  • Нормально ли использовать ещё один HOC, с Redux коннектом, хранящим ВСЁ состояние приложения?

    askhat
    @askhat
    SDE @ Akvelon
    будут считывать только нужное для себя

    Плохая идея. Таким образом сигнатура компонента будет определена не явно, а через тела его функций. Если компоненту требуется некоторый объект, он (компонент) должен явно сообщать об этом в пропс.
    Ответ написан
  • Какой backend лучше всего использовать с React.js/Redux?

    askhat
    @askhat
    SDE @ Akvelon
    Нет никакой разницы какой именно (подозреваю фреймворк) вы выберете. Главное чтобы протокол мог использоваться из браузера, а вы хорошо разбирались в выбранной технологии.
    Ответ написан
  • React context API vs mobX?

    askhat
    @askhat
    SDE @ Akvelon
    Mobx это реализация паттерна Observable, и ещё пара полезных функций. Если использовать Mobx можно отказаться реактовских setState и useState. Это полезно для того чтобы отделить модель от представления.

    React Context это реакт специфичная реализация Dependency Injection. Используя этот api вы можете передать компонентам заранее определённый объект в контекст (так будто этот объект был в аргументах [пропсах] компонента). В контексте может быть что угодно даже декорированный Mobx объект — стор.

    Говоря о Dependency Injection следует упомянуть Компоненты Высшего Порядка (HOC). Они выполняют ту же задачу — внедряют объект в область видимости функции. Однако в отличии от Context api используют прозрачный механизм каррирования.
    Ответ написан
  • Чем заменить функцию .map() в моем случае?

    askhat
    @askhat
    SDE @ Akvelon
    На вопрос ответил автор вопроса, я в свою очередь попытаюсь объяснить что произошло.

    Рендер в реакте всегда идёт по наименее трудозатратному пути, а именно вычисляет дельту (разницу) между новым стейтом и предыдущим, если таковой имеется. Например:

    class TodoList extends React.Component {
      state = {
        todos: [
          'Commit',
          'Push'
        ]
      }
      render() {
        return <ul>
          {this.state.todos.map(item => {
            return <li>{ todo }</li>
          }
        </ul>
      }
    }


    Если стейт компонента изменится, скажем при добавление элемента в начало списка todos, так что он станет таким:

    const todos = [
      'Init',
      'Commit',
      'Push'
    ]


    Реакт вычислит два древа VirtualDOM:

    // Начальный стейт
    <ul>
      <li>Commit</li>
      <li>Push</li>
    </ul>
    // Добавлен элемент
    <ul>
      <li>Init</li> // <- разница начинается здесь и до конца древа
      <li>Commit</li>
      <li>Push</li>
    </ul>


    Здесь выполняется работа которой можно было бы избежать. К примеру если бы элемент был добавлен в конец списка:

    const todos = [
      'Commit',
      'Push',
      'Merge'
    ]


    То реакт получил бы на сравнение другие два древа элементов:

    // Начальный стейт
    <ul>
      <li>Commit</li>
      <li>Push</li>
    </ul>
    // Добавлен элемент
    <ul>
      <li>Commit</li>
      <li>Push</li>
      <li>Merge</li> <- разница начинается здесь, от начала и до сих по ничего не менялось
    </ul>


    Дельта этих двух списков меньше, а значит и работы нужно сделать меньше.

    Совершенно очевидно что <li>Commit</li> и <li>Push</li> не менялись, однако реакт недостаточно умён чтобы это понять. Чтобы помочь ему следует воспользоваться специальным пропом key={}. Он может быть значением любого типа, единственно требование — значение должно стабильно идентифицировать соответствующие данные.

    Если бы компонент выглядел так:

    class TodoList extends React.Component {
      state = {
        todos: [
          { id: 0, text: 'Commit' },
          { id: 1, text: 'Push' }
        ]
      }
      render() {
        return <ul>
          {this.state.todos.map(item => {
            return <li key={todo.id}>{ todo.text }</li>
          }
        </ul>
      }
    }


    То добавление элемента в начало массива, породило бы следующий стейт:

    const todos = [
      { id: 2, text: 'Init' },
      { id: 0, text: 'Commit' },
      { id: 1, text: 'Push' }
    ]


    И, снова, два древа элементов:

    // Начальный стейт
    <ul>
      <li>Commit</li> // id 0
      <li>Push</li> // id 1
    </ul>
    // Добавлен элемент
    <ul>
      <li>Init</li> // id 2 новый элемент отобразится в начале
      <li>Commit</li> // id 0
      <li>Push</li> // id 1 
    </ul>


    Благодаря подсказке, реакт не учтёт в дельте элементы чьи идентификаторы не изменились, и, как следствие, не будет делать лишних действий.

    Таким образом использовать индекс в массиве в качестве ключа — не лучшая идея, особенно если массив будет меняться. По той же причине не следует использовать Math.random() в качестве ключа, так вы почти гарантировано будете всегда получать нестабильные идентификаторы.

    Подробнее об этом можно почитать здесь — Reconciliation.
    Ответ написан
  • Как изменить состояние во всех экземплярах компонента React?

    askhat
    @askhat
    SDE @ Akvelon
    Для этого каждому экземпляру нужно передать ссылку на одно значение

    class Buttons extends Component {
      state = {
        foo: 'bar'
      }
    
      changeText = () => {
        if (this.state.foo === 'bar') {
          this.setState({ foo: 'foo' })
        } else {
          this.setState({ foo: 'bar' })
        }
      }     
    
      render() {
        return (
          <Button text={this.foo} />
          <Button text={this.foo} />
          <Button text={this.foo} />
          <Button text={'Изменить текст'} onClick={this.changeText} />
        )
      }
    }


    Пример глупый, но принцип иллюстрирует.
    Ответ написан
  • Какое значение из input type=file передавать на сервер?

    askhat
    @askhat
    SDE @ Akvelon
    File это специальный тип Blob ~ MDN

    Вы можете использовать объект File в качестве аргумента метода #sendXMLHttpRequest, чтобы отправить его в теле POST запроса. Например:
    function eventHandler (event) {
      const file = event.files[0];
      const xhr = new XMLHttpRequest();
      xhr.open('POST', '/someroute', true)
      xhr.onreadystatechange = function () {
        if (xhr.status === 200) {
          console.log(xhr.reponseText);
        }
      }
    }
    xhr.send(file);
    Ответ написан