Thinking in Java: Learn React and React Hooks with Java Code ☕
Tags: java, javascript, react, webdev
Published: 2019-09-03 22:57:24

*As a long-time Java developer, it took me a while to understand some of the magics behind React. This post is my attempt to explain some of them in Java concepts. It's not meant to provide a strict mapping from Java to React.*

Below is a React `Counter` component. It renders a count number, with a button to increment it. Every time the button is clicked, the count is added by one and the value is updated on the screen.

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

class Counter extends React.Component<Props, State> {
  // 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 (
      <div>
        {this.state.currentCount}
        <button onClick={() =>
          this.setState({ currentCount: this.state.currentCount + 1 })
        }>
          Increment
        </button>
      </div>
    );
  }
}

// Renders Counter at root
const rootElement = document.getElementById("root");
render(<Counter initialCount={0} />, rootElement);
```
The same React component can be (sort-of) written in Java:

```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();
  }
  ...
}
```
To readers who have a Java background, table below maps some core React concepts into Java ones.

| React Concept | Java Concept |
|---------------|--------------|
| `component` | `class` |
| `props` | Passed-in `parameters` of constructor or `updateProps()` method, immutable internally  |
| `state` | A set of all `private variables`, immutable internally |
| `setState()` | Replaces the previous group of private variables with a new group |
| `render()` | Creates a new view with values applied |


A few interesting things to note here:

# `props` vs. `state`

In React, `props` are used for external world to communicate with the component, similar to Java constructor and public method parameters. In example above, it's used for setting its initial count value.

`state`, on the other hand, is used by the component internally, holding data that only matters to the component itself. This is similar to private variables in Java. However, a parent component's `state` can become a child component's `props`. E.g., `Counter`'s `currentCount` is passed into `Text` component as the latter's `props`.

Both `props` and `state` should be immutables internally. In React, we never change their internal values directly. Instead, pass in a new `props` to the component (example below), and use `setState()` for setting a new `state`. Note how they are internally `final` in Java code above.

# No Change, No Render

React only renders the component if either `props` or `state` has changed. This allows it to avoid unnecessary DOM updates. In above example, the component doesn't re-render until either button is clicked (a `state` change) or `initialCount` is changed (a `props` change). This is simulated using `shouldRender()` method above.

# Virtual DOM nodes

`render()` returns *virtual* nodes. They are objects that describes how a certain type of UI should be rendered. They are not the end results. It's up to the React engine to decide how UI will be generated and presented on the screen. This allows React to work with different platforms. E.g., React.js renders a Html `<button>` while React Native renders an Android `Button` or iOS `UIButton`.

# Handle `props` Changes

Now, let's briefly talk about React lifecycles. React provides several [lifecycle methods](https://reactjs.org/docs/react-component.html#the-component-lifecycle). Today we take a look at `componentDidUpdate()`.

Let's say we want the component to reset `state.currentCount` if the passed-in `props.initialCount` has changed. We can implement `componentDidUpdate()` as below:

```react
class Counter extends React.Component<Props, State> {
  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() {
    ...
  }
}
```

This may be written in Java as:

```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));
```
The external world calls `updateProps()` to update `Counter`'s `props`. Here, `updateProps()` preserves `prevProps`, and passes it into `componentDidUpdate()`. This allows the component to detect a `props` change and make updates accordingly.

Also note that setting new `props` doesn't require creating a new component instance. In the example above, the same `Counter` component is reused with new `props`. In fact, React tries to reuse existing components as much as possible using some smart DOM matching and the `key` props. It only creates new components when they cannot be found on the current DOM tree.

# React Hooks

If you are learning React, you must learn Hooks as it's the new standard (a good thing). Let's quickly look at the equivalent code in React Hooks:

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

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

  return (
    <div>
      {currentCount}
      <button onClick={() => setCurrentCount(currentCount + 1)}>
        Increment
      </button>
    </div>
  );
};
``` 
The code is just much conciser because many things are hidden behind each line.

The line below uses `React.useState()`. It kills two birds with one stone (sorry, birds 🥺). 

```react
  const [currentCount, setCurrentCount] = React.useState(initialCount);
```

- It sets `state.currentCount` as `initialCount` similar to the Java constructor, and
- returns a `setCurrentCount()` function that's equivalent to the `setState()` method used in Java. 

The benefit of using this pattern is that you can break down one single `state` object into multiple simple values, each controlled by its own `useState()` method.

Next, the lines below uses `React.useEffect()` to create an `effect`, which is run every time the component updates. 


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

In this case, the `effect` is tied to the `initialCount` value (note the last parameter of `useEffect()`). This tells `useEffect` to only run `setCurrentCount(initialCount)` when `initialCount` changes. This is equivalent to Java code below:

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

**There are many other magics in React and Hooks that go beyond this post. Leave a comment below if you'd like to learn more on this topic ❤️❤️❤️**