How to specify a constructor with a functional component (fat arrow syntax)?

Now that we have useState and hooks the answers are kind of out of date. I came across this question because I was doing something wrong. Here's some simplified code of what I was doing.

// set an initial state
const [ value, setValue ] = useState(0)

// gets called after component is re-rendered
useEffect(() => {
   // callback to parent that set props
   props.update()
})

// if we have an existing value passed in
if (props.value) {
   setValue(props.value)
}

This code was converted from a stateful class to a function using hooks, originally setting the default props in the constructor - but functions don't have constructors and that check happens every time the component re-renders:

  1. calls useState
  2. triggers re-render
  3. useEffect is triggerd
  4. parent is called which sets the props
  5. props update so child renders again
  6. GOTO 1

As you can see this results in an infinite loop. The solution is really quite simple. Here's a mock diff from the original.

- const [ value, setValue ] = useState(0)
+ const [ value, setValue ] = useState(props.value || 0)

- if (props.value) {
-   setValue(props.value)
- }

Basically, just initialise the state from the props and don't do silly things like calling useState except in response to an event or callback of some type.


Since it's a stateless component it doesn't have the component lifecycle. Therefor you can't specify a constructor.

You have to extend React.Component to create a stateful component which then will need a constructor and you'll be able to use the state.

Update Since React 16.8.0 and Hooks got introduced there are more options.

Hooks are a new feature proposal that lets you use state and other React > features without writing a class. They are released in React as a part of > v16.8.0

Stateless:

import React from "react"

const Stateless = ({name}) => (
  <div>{`Hi ${name}`}</div>
);

Stateful:

Has access to component lifecycle methods and local state.

class Stateful extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    const { count } = this.state;
    document.title = `You've clicked ${count} times.`;
  }

  componentDidUpdate() {
    const { count } = this.state;
    document.title = `You've clicked ${count} times.`;
  }

  render() {
    const { count } = this.state;
    return (
      <div>
        <p>You've clicked {count} times.</p>
        <button onClick={() => this.setState({ count: count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

Using Hooks:

Able to use State Hook and Effect Hook.

If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

import React, { useState, useEffect } from "react";

const UsingHooks = () => {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You've clicked ${count} times.`;
  });

  return (
    // <> is a short syntax for <React.Fragment> and can be used instead of a wrapping div
    <>
      <p>You've clicked {count} times.</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </>
  );
}