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:
- calls
useState
- triggers re-render
- useEffect is triggerd
- parent is called which sets the props
- props update so child renders again
- 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>
</>
);
}