I'm learning React hooks so in order to do that I'm trying to convert a class component to a functional component but I still get some errors.
Here is the original working component written as a class:
import React, { Component } from 'react';
import NavBar from './components/navbar';
import Counters from './components/counters';
class App extends Component {
state = {
counters: [
{ id: 0, value: 5 },
{ id: 1, value: 1 },
{ id: 2, value: 2 },
],
};
handleDelete = (counterId) => {
const counters = this.state.counters.filter((c) => c.id !== counterId);
this.setState({ counters });
};
handleReset = () => {
const counters = this.state.counters.map((c) => {
c.value = 0;
return c;
});
this.setState({ counters });
};
handleIncrement = (counter) => {
const counters = [...this.state.counters];
const index = counters.indexOf(counter);
counters[index] = { ...counter };
counters[index].value++;
this.setState({ counters });
};
render() {
return (
<React.Fragment>
<NavBar
totalCounters={this.state.counters.filter((c) => c.value > 0).length}
/>
<main className='container'>
<Counters
counters={this.state.counters}
onReset={this.handleReset}
onDelete={this.handleDelete}
onIncrement={this.handleIncrement}
/>
</main>
</React.Fragment>
);
}
}
export default App;
And this is the converted version which uses hooks.
import React, { useState } from 'react';
import NavBar from './components/navbar';
import Counters from './components/counters';
const App = () => {
const [counters, setCounters] = useState([
{ id: 0, value: 5 },
{ id: 1, value: 1 },
{ id: 2, value: 2 },
]);
const handleDelete = (counterId) => {
const counterss = counters.filter((c) => c.id !== counterId);
setCounters({ counterss });
};
const handleReset = () => {
const counterss = counters.map((c) => {
c.value = 0;
return c;
});
setCounters({ counterss });
};
const handleIncrement = (counter) => {
const counterss = [...counters];
const index = counterss.indexOf(counter);
counterss[index] = { ...counter };
counterss[index].value++;
setCounters({ counterss });
};
return (
<React.Fragment>
<NavBar totalCounters={counters.filter((c) => c.value > 0).length} />
<main className='container'>
<Counters
counters={counters}
onReset={handleReset}
onDelete={handleDelete}
onIncrement={handleIncrement}
/>
</main>
</React.Fragment>
);
};
export default App;
Most of it works fine but it keeps throwing an error saying that filter is not a function. Here it is the message:
TypeError: counters.filter is not a function
Converting to the functional component:Removed the class keyword and directly exported our component. Removed use of constructor and super. Changed how we were setting the state and used useState hook instead. Removed componentDidMount() and used useEffect hook instead.
You cannot use a class component with a functional component inside of it. Because they work different, for example. Inside a class based component you have the render method that returns an html. And in a functional component the return of the function is and html.
Of course, you can still pass props from parent to child with functional components but the big difference is that you'll need to declare them in your functional component callback just as you would with any other type of function. Now you can access those props.
You can convert this entire class into a functional React component using Hooks: Here, you have introduced the useState Hook. It allows you to make use of state in React functional components. With the useState () Hook, you can use state in this functional component. It uses a similar syntax with a destructuring assignment for arrays.
Function components are far less verbose, and require less boilerplate. They're (in my opinion) a bit more flexible with hooks and custom hooks, and they are (usually) a bit more performant. Note: in the examples below, I've shown how to import `React` and `Component`.
If, for example, you had two or more input fields for userName, firstName, and lastName, then you would have a class-based component with three state properties: To convert this class to a functional component with Hooks, you will have to take a somewhat unconventional route.
The class component needs to extend the React Component class, and must specify a render method. Whereas the function component is simply a function, and the render method is simply the return value of the function. Why convert a class component to a function component
The main culprit appears to be the way you are updating your state, which is like this:
setCounters({ counterss });
This will actually set your counters
state to an object with the property counterss
, so your state will contain the following:
{ counterss: [/* rest of the array */] }
The exact error being thrown is referring to the fact that you are attempting to call .filter
on an object instead of an array. To fix this issue you should simply update your state like this:
setCounters(counterss);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With