Source:  Twitter logo

In React, we can write components as pure functions. However, the problem with this is that you can't use it as stateful components because of the lack of lifecycle hooks and state. So, I wonder if is there any way to create stateful components without using classes.

Something that I found is the createClass helper. But, React has moved this helper into their own package in the release 15.5.0, link. Also, they recommend that you migrate them to JavaScript classes because classes are now the preferred way to create components in React. Therefore, I don't think that using this helper could be a good idea.

On the other hand, Facebook recommends the use of High Order Components (HOCs) which is an advanced technique in React for reusing component logic. HOCs are not part of the React API, per se. They are a pattern that emerges from React's compositional nature. But, I couldn't find a way to create common stateful components without classes.

Has anyone gone through this? Is there any way to use React as a some purely functional solution?

React supports this since version 16.8. From the documentation:

Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.

A simple example:

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

For an example of how to use lifecycles, check out useEffect

9 users liked answer #0dislike answer #09
Karamell profile pic
Karamell

Writing Stateful component without using classes is definitely a choice made by several developers. I recommend to use 'recompose' which has nice and easy implementation to write stateful components without class, yet apply state, both local and from store. Here is an example:

import compose from 'recompose/compose'
import withState from 'recompose/withState'
import withProps from 'recompose/withProps'

Pure.js

function MyComponent(props) ({

  local: { prop1, prop2 },
  setProp1 
})

  return <div>{prop1}</div>
}

const defaultState = {
  prop1: false,
  prop2: false
}

const enhance = compose(
  withState('local', 'updateLocal', defaultState),
  withProps(({ local: { prop1, prop2 }, updateLocal }) => ({
    setProp1: (newValue) => updateLocal(state => ({...state, prop1: newValue }))
  })))

export default enhance(MyComponent)
5 users liked answer #1dislike answer #15
Umesh profile pic
Umesh

Maybe react-instance can become handy. Take a look at examples below.

Save state in local variable:

import React from "react"
import instance from "react-instance"

const App = instance(({ forceUpdate }) => {
  let time = 0

  const timer = setInterval(() => {
    time++
    forceUpdate()
  }, 100)

  return {
    render() {
      return time
    },
    unmount() {
      clearInterval(timer)
    },
  }
})

Save state in component state:

import React from "react"
import instance from "react-instance"

const App = instance(instance => {
  instance.state = { time: 0 }

  const timer = setInterval(() => {
    instance.setState({ time: instance.state.time + 1 })
  }, 100)

  return {
    render() {
      return instance.state.time
    },
    unmount() {
      clearInterval(timer)
    },
  }
})
0 users liked answer #2dislike answer #20
pravdomil profile pic
pravdomil

I tried to create a simple stateful component named Comp without the usage of es6 classes.

Here is the code

Basically I'm linking the prototype of the Comp function (our stateful component) to the prototype object of React.Component and I pass down to it Comp's props to initialize it properly. After that you can use every function of the React.Component object on the Comp.prototype. I used some just an example. I don't know if this is the best way in the "most javascript" way to use react

0 users liked answer #3dislike answer #30
Alpe89 profile pic
Alpe89

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).