Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Given this component:

import React from 'react' import ReactDOM from 'react-dom' import PropTypes from 'prop-types'  const NewGoalInput = props => {   return (     <input type="text" onKeyUp={handleKeyUp}/>   ) }  const handleKeyUp = (e) => {   if (e.key === "Enter") {     // TODO Add goal   } }  export default NewGoalInput 

How do I add a constructor where I can define the state without using the extends React.Component syntax?

like image 845
Kenny Meyer Avatar asked May 30 '17 13:05

Kenny Meyer


People also ask

Can I use constructor in functional component?

When you're building functional components in React, there's a little feature from class-based components that simply has no out-of-the-box equivalent in functions. This feature is called a constructor.

How do you call a constructor in React?

In React, the constructor is called during component creation and before mounting. If you want to implement the constructor for a React component, call the super(props) method before any other statement. Otherwise, this. props will be undefined in the constructor and create bugs.

What is a component constructor?

The constructor is a method used to initialize an object's state in a class. It automatically called during the creation of an object in a class. The concept of a constructor is the same in React. The constructor in a React component is called before the component is mounted.


2 Answers

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>     </>   ); } 
like image 102
Hevar Avatar answered Sep 23 '22 18:09

Hevar


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.

like image 30
Richard Vanbergen Avatar answered Sep 24 '22 18:09

Richard Vanbergen