Refactoring the Filters Component

Learn how to refactor the filter component from a parent-child pattern to an internal state management pattern.

Current Filters component

Consider our current Filters component:

Press + to interact
import * as React from "react";
import { IFilter } from "../interfaces/IFilter";
export interface IFiltersProps<T> {
object: T;
properties: Array<IFilter<T>>;
onChangeFilter: (property: IFilter<T>, isChecked: boolean) => void;
}
export function Filters<T>(props: IFiltersProps<T>) {
const { object, properties, onChangeFilter } = props;
return (
<div className="p-1 my-2">
<label className="mt-3">Filters - try us too</label>
<br />
// for each key in object, generate a truthy / falsey
// checkbox pair
{Object.keys(object).map((key: any) => {
return (
<>
// truthy checkbox & label
<input
type="checkbox"
id={`${key}-true`}
value={key}
onChange={(event) =>
onChangeFilter(
{ property: key, isTruthySelected: true },
event.target.checked
)
}
// the 'some' function is used so that the checkbox can be checked
// if just one of the properties matches with 'isTruthySelected'
checked={properties.some(
(property) =>
property.property === key && property.isTruthySelected
)}
className="m-1 ml-3"
/>
// string interpolation here to generate a unique key
// and also the display contents of the label itself
<label htmlFor={`${key}-true`}>`${key} is truthy`</label>
// falsey checkbox & label
<input
type="checkbox"
id={`${key}-false`}
value={key}
onChange={(event) =>
onChangeFilter(
{ property: key, isTruthySelected: false },
event.target.checked
)
}
checked={properties.some(
(property) =>
property.property === key && !property.isTruthySelected
)}
className="m-1 ml-3"
/>
<label htmlFor={`${key}-false`}>`${key} is falsy`</label>
<br />
</>
);
})}
</div>
);
}

Refactoring Steps

Let’s make the Filters component responsible for its own state, like we did for the SearchInput and Sorters components. We’ll make the following changes:

  • Remove the object prop,
...