Vue.js developers' guide to React
Tags: react, vue
Published: 2020-10-24 16:52:33

---
title: Vue.js developers' guide to React
published: true
description: In this article, I introduce React way of implementing Vue.js features for Vue.js devs who want to learn React as well.
tags: react, vuejs
cover_image: https://hypertext-candy.s3-ap-northeast-1.amazonaws.com/posts/react-for-vuejs-developers/eye-catch.jpg
---

If you already learned one language or framework, it's easier to learn similar ones. Instead of reading docs from top to bottom, you just think, "how to do X with Y?".

In this article, I introduce React way of implementing Vue.js features for Vue.js devs who want to learn React as well.

(I don't encourage anyone to switch from Vue.js to React! It's better -- and also fun -- to getting to know both, right?)

## Components

### How to create a component?

#### Vue.js way

Vue component is consists of 3 blocks -- `<template>`, `<script>`, `<style>`. And the file should have `.vue` extension.

```html
<template>
  <div>
    <h1>Sample</h1>
    <h2>This is a component.</h2>
  </div>
</template>

<script>
export default {
  // data and behaviors.
}
</script>

<style>
/* how this component looks */
</style>
```

#### React way

In React, you have two ways to create components -- function and class.

Below is an exmaple of functional way of creating a component.

```jsx
import React from 'react';

function Sample() {
  return (
    <div>
      <h1>Sample</h1>
      <h2>This is a component.</h2>
    </div>
  );
}

export default Sample;
```

A functional component is a function that returns React element. It should looks like JavaScript returning HTML, but it's not. It's [JSX](https://ja.reactjs.org/docs/introducing-jsx.html).

In order to use JSX, you have to import React though it doesn't seem to be referenced directly. (But in React v17.0, you can choose not to import React just for JSX. Read [this official post](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) for details.)

Below is another way of creating react components with class syntax.

```jsx
import React from 'react';

class Sample extends React.Component {
  render() {
    return (
      <div>
        <h1>Sample</h1>
        <h2>This is a component.</h2>
      </div>
    );
  }
}

export default Sample;
```

Class component's `render` method returns React element.

So, what is the difference between the two and which way should you choose to write your own React components?

In v16.7 and below, class components have state management (`data` in Vue.js) and lifecycle methods -- both are crucial for useful components -- and functional ones didn't.

But, from v16.8, React introduced [Hooks](https://reactjs.org/docs/hooks-intro.html) into functional components. Hooks take care of state management and "side effects" (operations that should happen after rendering).

Although a few lifecycle methods are not "translated" in hooks, functional components can do pretty much the same jobs as class components. And React team recommends functional way for your first choice.

> When you’re ready, we’d encourage you to start trying Hooks in new components you write.
> In the longer term, we expect Hooks to be the primary way people write React components.
> <cite>[Should I use Hooks, classes, or a mix of both?](https://reactjs.org/docs/hooks-faq.html#should-i-use-hooks-classes-or-a-mix-of-both)</cite>

So if you start brand new React project, or you are a React beginner, I think you should consider writing in functional way first. And if you want to use class-only features, then introduce class components. It's totally OK that functional components and class components live together.

In this article, I explain about functional way.

### Templating

#### Vue.js way

Vue component's `<template>` has its own syntax such as `v-bind`, `v-for`, `v-if`.

```html
<template>
  <div>
    <h1>Hello, {{ name }} !</h1>
    <a :href="link">Click me</a>
    <ul>
      <li v-for="item in items" :key="item.key">
        {{ item.title }}
      </li>
    </ul>
    <p v-if="isActive">Paragraph</p>
    <p v-show="isShow">Second paragraph</p>
  </div>
</template>
```

#### React way

In React, you use JSX.

```jsx
return (
  <div>
    <h1>Hello, {name} !</h1>
    <a href={link}>Click me</a>
    <ul>
      {items.map(item => (
        <li key={item.key}>{item.title}</li>
      ))}
    </ul>
    {isActive && <p>Paragraph</p>}
    <p style={{ display: isShow ? 'initial' : 'none' }}>Second paragraph</p>
  </div>
);
```

- JSX is not a template engine. It has only one special syntax -- `{}` -- and the rest are just JavaScript.
- statement inside of `{}` is evaluated as JavaScript.
- There is no equivalent for `v-show`. So basically you should manually manipulate `display` of style attribute.
- I'll talk about CSS classes later.

Just like Vue's `<template>`, functional component must return only one root element. But React has convenient helper component `<React.Fragment>`. It lets you return multiple elements in order for you not to wrap elements with useless `<div>` only for the sake of a framework's requirement.

```jsx
return (
  <React.Fragment>
    <h1>...</h1>
    <h2>...</h2>
    <h3>...</h3>
  </React.Fragment>
);
```

`<React.Fragment>` is not rendered as DOM. You just get `<h1>`, `<h2>` and `<h3>` in the exmaple above.

And, `<React.Fragment>` has its syntax sugar. Its name can be omit. That is, the snippet above can be written as below.

```jsx
return (
  <>
    <h1>...</h1>
    <h2>...</h2>
    <h3>...</h3>
  </>
);
```

Odd but handy, huh?

### CSS classes

#### Vue.js way

Vue.js offers `v-bind:class` as a way to manipulate HTML `class` attribute.

```html
<button class="btn" :class="{ 'btn-primary': isPrimary }">...</button>
<button class="btn" :class="['btn-primary', 'btn-small']">...</button>
```

#### React way

There is no special way in React. `className` is just an equivalent for `class` attribute. `class` is one of reserved keywords in JavaScript so JSX calls this `className`.

```jsx
return <button className="btn btn-primary">...</button>;
```

Although, [classnames](https://github.com/JedWatson/classnames) library will help you dealing with HTML classes. 

```js
import classNames from 'classnames';
```

It's just like `v-bind:class`.

```js
const buttonClass = classNames({
  btn: true,
  'btn-primary': isPrimary
});

return <button className={buttonClass}>...</button>;
```

### HTML

#### Vue.js way

For injecting HTML string, you use `v-html` in Vue.js.

```html
<div v-html="htmlString"></div>
```

#### React way

In React, there is a prop named `dangerouslySetInnerHTML`. It literally warns you that inserting HTML string carelessly is a dangerous move. `dangerouslySetInnerHTML` accepts an object that has `__html` property with HTML strings as its value.

```js
return <div dangerouslySetInnerHTML={{ __html: htmlString }} />;
```

### Events

#### Vue.js way

In Vue.js, events are represented by `@` syntax (sugar for `v-on`).

```html
<button @click="handleClick">Click me</button>

<form @submit.prevent="handleSubmit">...</form>
```

#### React way

React takes more HTML-like approach. Event handler is passed to prop named onEventName -- e.g. `onChange`, `onSubmit`.

```jsx
const handleClick = e => {/* blah blah... */};

return <button onClick={handleClick}>Click me</button>;
```

There is no event modifiers like `.prevent`.

### States (data)

#### Vue.js way

In Vue.js, component's internal state is defined by a return value of the `data` method.

```html
<script>
export default {
  data() {
    return {
      count: 0
    }
  }
}
</script>
```

Inside other parts of the component, you can reference its state value through `this`.

```js
methods: {
  increment() {
    this.count += 1;
  }
}
```

#### React way

In React, you use [`useState`](https://reactjs.org/docs/hooks-state.html) hook. Hey, here comes the hook!

```js
import React, { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0);

  const handleClick = () => setCount(count + 1);

  return <button onClick="handleClick">{count}</button>;
}
```

Hooks are functions for accessing React's magic. `useState` is the one for managing component's state. 

`useState` takes state's default value as an argument, and returns array that contains 0. "state variable" and 1. "function that update state". State's value can only be updated through that function.

Call `useState` by individual states.

```js
const [name, setName] = useState("John Doe");
const [age, setAge] = useState(20);
```

You can set object as state's value.

```js
const [user, setUser] = useState({ name: "John Doe", age: 20 });
```

### Forms

#### Vue.js way

In Vue.js, `v-model` handles form inputs.

```html
<input type="text" v-model="name" />
```

`v-model` lets you implement bi-directional data flow.

#### React way

React doesn't introduce sytax sugar for bi-directional data update. You have to implement it on your own by combining state and event.

```js
const [name, setName] = useState('');
const handleInput = e => setName(e.target.value);

return <input type="text" onChange="handleInput" value="name" />;
```

It's a bit annoying writing this boilerplate almost everytime dealing with forms. But I think this kind of simplicity, or "give you no sugar", "write what you need on your own as possible" style is very React-ish.

### methods

#### Vue.js way

Inside of methods defined in `methods`, you can reference states (`data`). And the methods can be referenced inside your template.

```html
<script>
export default {
  methods: {
    sayHello() {
      console.log(`Hello, ${this.name}!`)
    }
  }
}
</script>
```

#### React way

There's nothing like Vue's `methods` in React. React component is essentially just a JavaScript function, so you treat it as it is.

```js
function MyComponent() {
  const [name, setName] = useState('John');

  function sayHello() {
    console.log(`Hello, ${name}!`);
  }

  return <button onClick={sayHello}>...</button>;
}
```

### ref

#### Vue.js way

In Vue.js, `ref` gives you direct access to the DOM.

```html
<template>
  <div>
    <div ref="foo">...</div>
    <button @click="handleClick">Click me</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleClick() {
      console.log(this.$refs.foo);
    }
  }
}
</script>
```

#### React way

React has similar functionality as Vue's `ref`.

With [`useRef`](https://reactjs.org/docs/hooks-reference.html#useref) hook, you can create a "ref object" for accessing DOM. The object's `current` property contains reference for the DOM.

```js
import React, { useRef } from 'react';

function MyComponent() {
  const target = useRef(null);

  const handleClick = () => {
    console.log(target.current);
  };

  return (
    <>
      <div ref={target}>...</div>
      <button onClick={handleClick}>Click me</button>
    </>
  );
}

export default MyComponent;
```

### computed properties

#### Vue.js way

Vue.js has "computed properties".

```html
<p>Hello, {{ fullName }} !</p>
```

```js
export default {
  data() {
    return {
      firstName: 'John',
      lastName: 'Doe'
    };
  },
  computed: {
    fullName() {
      return `${this.firstName} ${this.lastName}`;
    }
  }
}
```

Computed properties are functions that capture the results of computation, and behave like properties in the template block.

#### React way

I think [`useMemo`](https://reactjs.org/docs/hooks-reference.html#usememo) hook is React version of "computed property".

```js
import React, { useMemo } from 'react';

function MyComponent() {
  const [firstName, setFirstName] = useState("John");
  const [lastName, setlastName] = useState("Doe");

  const fullName = useMemo(() => {
    return `${firstName} ${lastName}`;
  }, [firstName, lastName]);

  return <p>Hello, {fullName} !</p>;
}
```

`useMemo` takes function as 1st argument and array as 2nd argument, and returns [memoized](https://en.wikipedia.org/wiki/Memoization) value.

- React's functional component is re-rendered everytime props or states are updated.
- But a function of `useMemo`'s 1st argument only be re-calculated when values in an array passed as 2nd argument are updated.
- If the values in 2nd argument array are not updated, cached value will be returned.

This behavior is similar to Vue's computed property, but it's not so much common pattern as computed property. You should use `useMemo` only when there's a real need for optimization (I learned this from [this post](https://kentcdodds.com/blog/usememo-and-usecallback)).

### watch

#### Vue.js way

Vue.js offers you watchers -- "more generic way to react to data changes".

```js
export default {
  watch: {
    name(valueAfterUpdate, valueBeforeUpdate) {
      // ...
    }
  }
}
```

#### React way

React has no equivalent for watchers.

You can implement something like that using `useEffect` hook. I will show you that hook in next section.

But I oftern think that there're not so many use-cases for the `watch` option, because most of the time, it can be replaced with on-change event.

## Lifecycles

### Vue.js way

Vue.js has many lifecycle hooks.

```js
export default {
  created() {/* ... */},
  mounted() {/* ... */},
  updated() {/* ... */},
  destroyed() {/* ... */}
}
```

### React way

In React functional component, there is no concept of lifecycle. It's much simpler here.

- functional component is rendered and re-rendered when its props or states are updated.
- if you want to do something just after rendering, put that operation in the [`useEffect`](https://reactjs.org/docs/hooks-effect.html) hook.

```jsx
import React, { useState, useEffect } from 'react';

function MyComponent() {
  const [items, setItems] = useState([]);

  useEffect(() => {
    someApi.getItems().then(response => {
      setItems(response.data);
    });
  }, []);
```

`useEffect` behaves differently depending on what is passed as a 2nd argument.

```js
// if there is no 2nd argument,
// 1st argument is called on every renders.
useEffect(() => {});

// if 2nd argument is an empty array,
// 1st argument is called only on first render.
useEffect(() => {}, []);
// this is like "mounted" in Vue.js

// if 2nd argument contains one or more items,
// 1st argument is called on first render and when the items are updated.
useEffect(() => {}, [aaa, bbb]);
// this is like "mounted" plus "updated" & "watch", I guess.
```

`useEffect`'s 1st argument can return "clean up" function, that is called just before its component is removed from the DOM.

```jsx
import React, { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    // ...

    return () => {
      // clean up function.
      // this is like "destroyed" in Vue.
    };
  }, []);

  return <div>...</div>;
}
```

On the other hand, class components have `constructor` and lifecycle methods that work just like Vue.js. I don't show you around in this article, but you can learn about these from [this post](https://reactjs.org/docs/react-component.html#the-component-lifecycle).

## Interaction between components

### props

#### Vue.js way

`props` option is used for passing data from parent component to its child.

```html
<Child :name="test" :item="sampleData" />
```

```html
<script>
function Item(one, two) {
  this.one = one
  this.two = two
}

export default {
  // validate its value with "type" and "required".
  props: {
    name: {
      type: String,
      required: false,
      default: 'John Doe'
    },
    item: {
      type: Item,
      required: true
    }
  }
}
</script>
```

#### React way

In React, properties / attributes passed from parent to children are also called `props`.

```html
<Child name={test} item={sampleData} />
```

1st argument of a functional component is the props.

```jsx
import React from 'react';

function Child(props) {
  // props.name
  // props.item
}
```

You can use [prop-types](https://github.com/facebook/prop-types) library for validation.

```jsx
import React from 'react';
import PropTypes from 'prop-types';

function Child(props) {
  // props.name
  // props.item
}

Child.propTypes = {
  name: PropTypes.string,
  item: PropTypes.shape({
    one: PropTypes.string.isRequired,
    two: PropTypes.number.isRequired
  }).isRequired
};

Child.defaultProps = {
  name: 'John Doe'
};

export default Child
```

### emitting events

#### Vue.js way

In Vue.js, child component notifies event with `$emit` method to its parent.

```js
onSomethingHappened() {
  this.$emit('hello');
}
```

Then, register a handler for a notified event with `@` syntax.

```html
<Child @hello="parentMethod" />
```

#### React way

React has no syntax for event emitting. You just pass a handler function as a prop -- i.e. parent component determine what to do and children execute that.

```jsx
function Child({ onHello }) {
  const handleClick = () => {
    console.log('hello there');
    onHello();
  };

  return <button onClick={handleClick}>click me</button>;
}
```

```html
function Parent() {
  const parentMethod = () => {/* blah blah... */};

  return <Child onHello={parentMethod} />;
}
```

### slot

#### Vue.js way

Vue.js has `slot` for inserting child elements.

```html
<Content>
  <p>Hello world</p>
</Content>
```

`Content` component be like:

```html
<template>
  <article>
    <h1>This is a title.</h1>
    <slot></slot>
  </article>
</template>
```

When you have more that one blocks to insert, you can name each of those.

```html
<MyComponent>
  <template #header>
    <MyHeader />
  </template>
  <template #content>
    <MyContent />
  </template>
  <template #footer>
    <MyFooter />
  </template>
</MyComponent>
```

#### React way

In React, `children` prop has inserted elements.

```jsx
<Content>
  <p>Hello world</p>
</Content>
```

```jsx
function Content({ children }) {
  // children -> <p>Hello world</p>
  return (
    <article>
      <h1>This is a title.</h1>
      {children}
    </article>
  );
}
```

You can neither have multiple `children` nor name it.

But `children` is just a prop. The example above is essentially same as below:

```jsx
<Content children={<p>Hello world</p>} />
```

So you can just do this for inserting multiple elements.

```jsx
return (
  <MyComponent
    header={<MyHeader />}
    content={<MyContent />}
    footer={<MyFooter />}
  />
);
```

```jsx
function MyComponent({ header, content, footer }) {
  return (
    <div>
      <header>{header}</header>
      <main>{content}</main>
      <footer>{footer}</footer>
    </div>
  )
}
```

## Wrapping up

Here is my impression:

- React is much simpler than Vue.js, and, more rooms for you to improvise.
- Vue.js has more APIs but is more easy to learn.

In that sense, I think Vue.js is well designed. I recommend Vue.js especially for new JS framework learners. It's also my first JS framework that I succeeded to learn (I failed with angular.js before that).

But, now I like React more. It's simple and enough.

Which one do you prefer?

So, that's all folks! Thanks for reading. Hope you enjoyed and this helps your learning!