Можно ли хранить большой объем данных в useState?
Дано: Приложение со списками задач. Списков может быть сколько угодно - их создает пользователь. Все списки я храню в useState:
const [folders, setFolders] = useState([{'id': 0, 'folderName': 'Frontend', 'tasksList': ['create repo', 'learn TS']}, {'id': 1, 'folderName': 'Backend', 'tasksList': ['learn Python']}]);
Данный стейт хранится в корневом компоненте App и используется во всех дочерних компонентах для отображения этих списков и задач.
Проблема: Пользователь постоянно добавляет списки и задачи в эти же списки - из-за чего стейт сильно разрастается, становится нечитаемым для разработчика.
Для полного понимания, вот код компонента App:
function App() {
const [folders, setFolders] = useState([{'id': 0, 'folderName': 'Frontend', 'tasksList': ['create repo', 'learn TS']}, {'id': 1, 'folderName': 'Backend', 'tasksList': ['learn Python']}]);
const [currentFolder, setCurrentFolder] = useState();
const chooseFolderHandler = (folderId) => {
setCurrentFolder(folders[folderId]);
};
const deleteFolderHandler = (folderId) => {
const folderFiltered = folders.filter(elem => elem.id !== folderId);
setFolders(folderFiltered);
};
return (
<div className='app'>
<Header />
<div className='desktop'>
<Menu
onDelete={deleteFolderHandler}
onClick={chooseFolderHandler}
folders={folders}
currentFolder={currentFolder}/>
<Display
currentFolder={currentFolder}/>
</div>
</div>
);
}
ВОПРОС: Как организовать хранение списков в стейте в связке с их названием и id, чтобы стейт не разрастался до гиганстких размеров? Или же это нормальная практика?
Заранее спасибо!
Ответы (1 шт):
Лучше не использовать подобные стейты. useState предназначен для хранение простых типов данных, т.к. для его корректного обновления требуется полностью переписывать его значение, а для объекта - отдублировать его, что плохо скажется на производительности.
Хороший вариант - использовать ReactRedux или ReduxToolkit. Это очень быстро работает и легко использовать.
Альтернативный вариант:
const store = {
callbacks: new Set(), // тут хранятся слушатели
state: [
{'id': 0, 'folderName': 'Frontend', 'tasksList': ['create repo', 'learn TS']},
{'id': 1, 'folderName': 'Backend', 'tasksList': ['learn Python']}
],
emitAll() {
Array.from(this.callbacks).map(call => call(this.state)); // заставляем стейты из useTasks обновиться до актуальных значений
},
setState(newState) { // обновляем данные в стейте. newState может быть как функцией (prevState) => newState | prevState, так и новым значением
if (typeof newState === "function") {
const result = newState(this.state);
if (result !== newState) {
this.state = result;
this.emitAll();
}
} else {
this.state = newState;
this.emitAll();
}
},
subscribe(func){ // подписываемся на изменения при маунте и отписываемся при дидмаунте
if (this.callback.has(func)) return;
this.callback.add(func);
return () => {
this.callback.delete(func)
}
}
}
const useTasks = (callback) => { // хук получения задач
const [state, setState] = useState(callback(store.state));
useEffect(() => { // подписываемся на изменения стора
return store.subscribe((state) => {
setState(callback(store.state)); // обновляем стейте
});
}, [callback]);
return useMemo(() => state, [state]);
}
//Use
const Component = () => {
const task = useTasks(state => state['0']); // получишь задачу с id 0
return <span>{task.folderName}</span>
}