Converting a class component to a functional one

Viewed 58

Here an example of some code at https://codepen.io/vasilly/pen/LkZKzj

I am trying to figure out how to change the Main class to a functional component, but I am stuck on how to convert

setCategory(category) {
    this.setState({
      displayCategory: category
    });
  }

on lines 72 - 76.

Does anyone have any suggestions on how to accomplish this? I am new to react and trying o figure out the best way to do this.

2 Answers

the state methods can be replaced with React hooks, specifically, the useState hook

I'll recommend you to check the docs, but the main points to keep in mind are

  • there's no this (so no more .bind(this)!)
  • everything are functions

and the rules of hooks

  • hooks can only be called from react functions (not from plain js functions). That is, call them from functional components, or other hooks
  • hooks have to be called always in the same order, meaning you can't conditionally call hooks (like inside an if) nor in loops). Because of this, they have to also be called in the "top" level of the component (meaning, they can't be called inside a function defined in your component)

With that in mind, let's see how you'd replace the state. To do so, you can use the useState hook.

const [displayCategory, setDisplayCategory] = useState('all');

The unique parameter is the initialValue for your state. This one is optional, if no default value is provided, it would be the same as providing undefined.
As you can see, it returns an array of two elements, what we are doing here is destructuring; it's the same as doing

const stateHook = useState('all')
const displayCategory = stateHook[0]
const setDisplayCategory= stateHook[1]

That means you can name whatever you want those variables. Now, displayCategory is your actual state value. You can use it as you'd use this.state.displayCategory. And setDisplayCategory is the function that lets you update your state.

One of the differences to keep in mind is that the functions to update the state in hooks will override the entire state - meaning there's no merging of state as there was in classes. This is especially important for objects. So something like this

const [state, setState] = useState({ foo: 1, baz: 2 })
// later in one event
setState({ baz: 3 })

There, on the next render, the value of state will be { baz: 3 } - the previous was lost

In order to preserve the state, the second parameter from the array returned from useState (meaning, the setState, setDisplayCategory, or whatever you call it), accepts a callback in which you can manually do the merging of properties. Like this

setState(prevState => ({ ...prevState, baz: 3 })

Now, in the next render, the value of your state will be { foo: 1, baz 3 }

Modeling complex states

Before hooks, you could only have one state. Therefore, everything you wanted to store in your state had to belong to this unique object. However, with hooks, you're allowed to have multiple states. For example, following your code, you could have something like this

const [displayCategory, setDisplayCategory] = useState('all')
const [products, setProducts] = useState([])
const [myComplexObject, setMyComplexObject] = useState({ foo: 1, baz: 2, bar: [1, 2, 3] })

Considering this, and the fact that the properties are not automatically merged, it's convenient to group state objects/variables/properties that change together under the same useState object. This gives more flexibility, especially when passing different portions of your state to different child components - you could save some rerenders when, for those components, the props don't change

In functional components, you have hooks that you can use for this purpose. You can use the useState() to initialize your state variables. In functional component, the code snippet would look something like this -

const [displayCategory, setDisplayCategory] = useState('defaultStateValue');
const setCategory = (category) => {
    setDisplayCategory(category);
}

In the above code snippet, you are just initializing your state variables and the state variable setter function using the useState() hook. Then you call setDisplayCategory() and pass it the parameter that you want your state variable displayCategory to be updated to. You should initialize all your other state variables in Main component in a similar fashion.

You should read more on hooks here - https://reactjs.org/docs/hooks-intro.html and get yourself familiar with those as it would be used in functional components frequently,

Related