Рубрики
Без рубрики

Мышление на языке Java: Изучайте крючки React и React с помощью кода Java ☕

Как давнему разработчику Java, мне потребовалось некоторое время, чтобы понять некоторые волшебства, лежащие в основе React. Этот… Помеченный java, javascript, react, webdev.

Как давнему разработчику Java, мне потребовалось некоторое время, чтобы понять некоторые волшебства, лежащие в основе React. Этот пост – моя попытка объяснить некоторые из них в концепциях Java. Он не предназначен для обеспечения строгого сопоставления Java с React.

Ниже приведен компонент React Счетчик . Он отображает число подсчета с кнопкой для его увеличения. Каждый раз, когда нажимается кнопка, количество добавляется на единицу, и значение обновляется на экране.

type Props = { initialCount: number };
type State = { currentCount: number };

class Counter extends React.Component {
  // Sets currentCount to initialCount when component is created
  state: State = { currentCount: this.props.initialCount };

  // Renders a text and a button, which increments count by one when clicked.
  render() {
    return (
      
{this.state.currentCount}
); } } // Renders Counter at root const rootElement = document.getElementById("root"); render(, rootElement);

Один и тот же компонент React может быть (вроде как) написан на Java:

// The Props class to pass data into Counter, publicly construct-able.
public class Props {
  public final int initialCount;
  public Props(int initialCount) { this.initialCount = initialCount; }
}

public class Counter {
  // The State class to hold internal data of Counter, private only.
  private static class State {
    final int currentCount;
    State(int count) { this.currentCount = count; }
  }

  private State state;
  private Props props;
  private boolean shouldRender;

  // Constructor. Called once per component lifecycle.
  public Counter(final Props props) {
    this.updateProps(props);
    this.setState(new State(props.initialCount));
  }

  // Called by external whenever props have changed.
  public void updateProps(final Props props) {
    this.props = new Props(props.initialCount);
    this.shouldRender = true;
  }

  // Internal state update method for current count.
  private void setState(final State newState) {
    this.state = newState;
    this.shouldRender = true;
  }

  // Only allows render when shouldRender is true, i.e., props or state changed.
  public boolean shouldRender() {
    return this.shouldRender;
  }

  // Returns a 'virtal DOM' node 'Div' that contains a 'Text' node and a 'Button',
  // which increments count by one when clicked.
  public ReactNode render() {
    this.shouldRender = false;
    return new Div(
      new Text(this.state.currentCount),
      new Button("Increment", new OnClickHandler() {
        @Override
        public void onClick() {
          setState(new State(state.currentCount + 1));
        }
      });
    );
  }
}

// Renders Counter at root
public static void renderAt(HTMLElement root) {
  Counter counter = new Counter(new Props(0));
  root.addChild(counter);
  if (counter.shouldRender()) {
    counter.render();
  }
  ...
}

Для читателей, имеющих опыт работы с Java, в таблице ниже некоторые основные концепции React сопоставлены с концепциями Java.

класс компонент
Переданные параметры конструктора или метода update Props(), неизменяемые внутренне реквизит
Набор всех частных переменных, неизменяемых внутренне государство
Заменяет предыдущую группу частных переменных новой группой Установить состояние()
Создает новое представление с примененными значениями визуализация()

Здесь следует отметить несколько интересных вещей:

В React реквизиты используются для взаимодействия внешнего мира с компонентом, аналогично параметрам конструктора Java и общедоступного метода. В приведенном выше примере он используется для установки начального значения счетчика.

состояние , с другой стороны, используется компонентом внутренне, храня данные, которые важны только для самого компонента. Это похоже на частные переменные в Java. Однако состояние родительского компонента может стать реквизитом дочернего компонента . Например, Счетчик ‘s текущее количество передается в Текст компонент в качестве последнего реквизита .

Оба реквизита и состояние должны быть внутренне неизменяемыми. В React мы никогда напрямую не меняем их внутренние ценности. Вместо этого передайте компоненту новый реквизит (пример ниже) и используйте setState() для установки нового состояния . Обратите внимание, как они внутренне окончательны в приведенном выше коде Java.

React отображает компонент только в том случае, если либо реквизит или состояние изменилось. Это позволяет избежать ненужных обновлений DOM. В приведенном выше примере компонент не выполняет повторную визуализацию до тех пор, пока не будет нажата либо кнопка ( состояние изменение), либо начальное количество изменено (a реквизит изменение). Это моделируется с использованием метода should Render()

функция render() возвращает виртуальные узлы. Это объекты, которые описывают, как должен отображаться определенный тип пользовательского интерфейса. Они не являются конечными результатами. Движок React должен решить, как будет создаваться и отображаться пользовательский интерфейс на экране. Это позволяет React работать с различными платформами. Например., React.js отображает Html <кнопка> в то время как React Native отображает кнопку Android или iOS UIButton .

Теперь давайте кратко поговорим о жизненном цикле React. React предоставляет несколько методов жизненного цикла . Сегодня мы рассмотрим componentDidUpdate() .

Допустим, мы хотим, чтобы компонент был сброшен Допустим, мы хотим, чтобы компонент был сброшен если переданный если переданный изменился. Мы можем реализовать componentDidUpdate()

class Counter extends React.Component {
  state: State = { currentCount: this.props.initialCount };

  // After props changed, check if initialCount has changed, then reset currentCount to the new initialCount.
  componentDidUpdate(prevProps: Props) {
    if (prevProps.initialCount !== this.props.initialCount) {
      this.setState({ currentCount: this.props.initialCount });
    }
  }

  render() {
    ...
  }
}

Это может быть написано на Java как:

class Counter {
  ...
  // Called by external whenever props have changed.
  public void updateProps(final Props props) {
    final Props prevProps = this.props;
    this.props = new Props(props.initialCount);
    this.shouldRender = true;
    this.componentDidUpdate(prevProps);
  }

  private void componentDidUpdate(final Props prevProps) {
    if (prevProps.initialCount != this.props.initialCount) {
      setState(new State(this.props.initialCount));
    }
  }
  ...
}
Counter counter = new Counter(new Props(0));
counter.updateProps(new Props(100));

Внешний мир вызывает обновление реквизита() для обновления счетчика реквизита . Здесь updateprops() сохраняет prevProps и передает его в componentDidUpdate() . Это позволяет компоненту обнаруживать изменения реквизита и вносить соответствующие обновления.

Также обратите внимание, что установка нового реквизита не требует создания нового экземпляра компонента. В приведенном выше примере то же самое Счетчик компонент повторно используется с новыми реквизитами . Фактически, React пытается максимально использовать существующие компоненты повторно, используя некоторые интеллектуальные сопоставления DOM и ключ реквизит. Он создает новые компоненты только в том случае, если они не могут быть найдены в текущем дереве DOM.

Если вы изучаете React, вы должны изучить крючки, так как это новый стандарт (хорошая вещь). Давайте быстро рассмотрим эквивалентный код в крючках React:

const Counter = ({ initialCount }: Props) => {
  const [currentCount, setCurrentCount] = React.useState(initialCount);

  React.useEffect(() => {
    setCurrentCount(initialCount);
  }, [initialCount]);

  return (
    
{currentCount}
); };

Код просто намного сложнее, потому что за каждой строкой скрыто много вещей.

В строке ниже используется React.использовать состояние() . Это убивает двух зайцев одним выстрелом (извините, птицы 🥺).

  const [currentCount, setCurrentCount] = React.useState(initialCount);
  • Он устанавливает Он устанавливает как
  • начальный счетчик аналогично конструктору Java, и возвращает установите функцию CurrentCount() , эквивалентную методу

Преимущество использования этого шаблона заключается в том, что вы можете разбить один объект состояние на несколько простых значений, каждое из которых управляется своим собственным методом useState() .

Далее, в трех строках ниже используется React.use Effect() для создания эффекта , который запускается при каждом обновлении компонента.

  React.useEffect(() => {
    setCurrentCount(initialCount);
  }, [initialCount]);

В этом случае эффект привязан к значению начального количества (обратите внимание на последний параметр использовать эффект() ). Это указывает использовать эффект только для запуска setCurrentCount(начальное количество) когда начальный подсчет

  private void componentDidUpdate(final Props prevProps) {
    if (prevProps.initialCount != this.props.initialCount) {
      setState(new State(this.props.initialCount));
    }
  }

В React и крючках есть много других магических приемов, которые выходят за рамки этого поста. Оставьте комментарий ниже, если вы хотите узнать больше по этой теме ❤️ ❤️ ❤️

Оригинал: “https://dev.to/getd/thinking-in-java-learn-react-and-react-hooks-with-java-code-1ohf”