Skip to main content

Filters

In this part you'll learn how to correctly manage your state without sacrificing performance

Creating component

Let's create component, which will contain filters:

Filters.jsx
import { useCallback } from 'react';
import { useStockState } from 'stocked';

export const Filters = () => {
const [titleFilter, setTitleFilter] = useStockState('filters.title');

const onChange = useCallback((e) => {
setTitleFilter(e.target.value);
}, [setTitleFilter]);

return (
<div>
<input placeholder="Search..." value={titleFilter} onChange={onChange} />
</div>
);
}

And, let's use new component in our App:

App.jsx
import { Filters } from "./Filters";

// ...

function App() {
return (
<StockRoot
initialValues={{
/** ... */
filters: {
title: ''
}
}}
>
<h1>Todo list!</h1>
<NewTodo />
<Filters />
<TodoList />
</StockRoot>
);
}

export default App;

How it looks like:

Filters result

However, currenlty our todo list is not filtered. That's because TodoList component does not respond to the filter's changes.

Let's fix it!

Modifing TodoList component

Currently, our TodoList depends only on length of todos. However, now, we need to make this component re-render each time, when filters are changing. To do this, stocked has function watch, which lets you to observe some value from stock.

TodoList.jsx
import { useCallback, useEffect, useState } from "react";
import { useStockContext } from "stocked";
import { TodoItem } from "./TodoItem";

export const TodoList = () => {
const { watch, getValue } = useStockContext();

const [visibleKeys, setVisibleKeys] = useState(() =>
getValue("todos").map((_, index) => index)
);

const filterItems = useCallback(
(filterTitle) => {
const allTodos = getValue("todos");

const newKeys = allTodos
.map((value, index) => ({ ...value, index }))
.filter(({ title }) =>
title.toLowerCase().includes(filterTitle.toLowerCase())
)
.map(({ index }) => index);

setVisibleKeys(newKeys);
},
[getValue]
);

useEffect(
// observing length of array
() => watch("todos.length", () => filterItems(getValue("filters.title"))),
[watch, filterItems, getValue]
);

// observing filter
useEffect(() => watch("filters.title", filterItems), [watch, filterItems]);

return (
<ul>
{visibleKeys.map((key) => (
<TodoItem key={key} index={key} />
))}
</ul>
);
};

Final result

And that's it the final result

Filters final result