В Jupiter изграждаме нови инструменти за фитнес треньори, за да улесним управлението на клиентите си. Работим по пускането на нашето приложение и то ще излезе доста скоро! Наскоро изграждахме функция за създаване на нови тренировки, които имаха множество вложени компоненти, където трябваше динамично да добавяме или изтриваме компоненти, както и да приемаме информация от потребителя. След като заснемем формуляра, ще трябва да го публикуваме в нашия бекенд, което означава, че ще трябва да имаме един изглед на всички данни.

Проблемът

Като начало имахме Workout Object, който е компонент от най-високо ниво. Трябваше да заснемем формуляр, в който потребителите да могат динамично да добавят или премахват компоненти, както и да актуализират своите полета според изискванията. Сега можем да направим това с Hooks, но ще трябва да съхраним състоянието в родителския обект и след това да го предадем на 2 нива надолу, за да можем да съхраним целия отговор в компонента Workout.

Една от причините, поради които трябва да бъде в компонента Workout, е, че ще трябва да съберем всички данни, преди да можем да ги изпратим обратно към бекенда, така че трябва да имаме общ преглед на всички входни данни, които ще вземем детските компоненти. Опитахме се да приложим това с кукички, но знаехме, че ще трябва да напишем много други компоненти в бъдеще, които ще имат подобни модели, и си струваше да инвестираме в библиотека за управление на състоянието.

Решението

Въведете hookstate. Какво е hookstate? Е, това не е „API за кукички“, който е създаден от React. Може би затова не виждате тази библиотека в първите 2 страници в Google. Но това е наистина проста, лека библиотека и може да бъде доста страхотна за определени случаи на употреба. Въпреки че аз лично обичам куките, това не е идеално за вложени или дълбоко вложени компоненти.

Ето кода по-долу за това, което се оказа наистина просто решение.

//WORKOUT.JS
import { useState } from “@hookstate/core”;
//The initial state of the workout component, which creates an //exercise with a name and it has a description. This is an array //which contains components of exercises. Each exercise component //creates an array of set objects.
export default function Workout() {
const state = useState([
{
name: “”,
desc:””,
sets: [{ reps: 10, weight: 0 },],
},]);
//We also create a new Exercise component every time the user clicks //a button. By default, each set has 12 reps and 0 additional //weight.
const createExercise = () => {
state.merge([{
name: “”,
sets: [{ reps: 12, weight: 0 }],},]);};
//Finally we map the exercise component and pass the exercise object //as props, I'll explain the benefits of passing the object in a //second.
return(
{state.map((exercise, index) => {
return <Exercise key={index} exercise={exercise}></Exercise>;
})}
<Button title=”Add Exercise” onPress={() => createExercise()} />
    );
}

Това е основен React и всъщност не правим нищо различно, освен факта, че използваме библиотеката Hookstate.

Това е мястото, където използването на Hookstate наистина изплати дивиденти! Концепцията за „състояние с обхват“ наистина опрости кодовата база. Накратко, той преобразува реквизитите за упражнение в обект, който може да се записва (Все пак така си го мисля аз!) само с един ред код.

import { useState, none } from "@hookstate/core";
export default function Exercise({ exercise }) {
const exerciseState = useState(exercise);
//An exercise can have multiple sets and we can easily create this //with the merge function, which adds new Set objects to the end of //the array.
const handleAddSets = () => {
exerciseState.nested(“sets”).merge([{ reps: 10, weight: 0 }]);
console.log(“add sets”);
};
//We also needed to delete an Exercise component. The user needs to //be able to interact with the component. Here we can use //hookstate's set() function and delete the item by using none //object.
const handleDeleteExercise = () => {
exerciseState.set(none);
};
//In here, we pass the exercise name value and also track it when //the text changes.
return(
<TextInput
style={styles.exerciseDescription}
placeholder="Exercise name"
value={exerciseState.name.value}
onChangeText={(e) => exerciseState.name.set(e)}
/>
{exerciseState.sets.map((sets, index) => (
<Set key={index} sets={sets} index={index + 1} />))}
);}

Ние правим същото нещо тук, когато предаваме обекта Set към компонента Set, така че да можем да получим стойността на повторенията и теглото за всеки комплект, както и възможността да изтриваме набори.

export default function Set({ sets, index }) {
const setsData = useState(sets);
//Ability to delete sets
const handleDeleteSets = () => {
setsData.set(none);
};

Така че по същество hookstate направи супер лесно управлението на състоянието на различни компоненти. Имаме 3 компонента и можем динамично

  • Уловете въведеното от потребителя
  • Добавете нови компоненти
  • Изтрийте текущите компоненти

Можем да направим това само с 20 реда код.

Няма шаблонен код и изглежда React-ish и е лесно да се прочете какво прави.

Аз лично се борих да разбера как работи API, тъй като няма толкова много документация за библиотеката, колкото има за други, така че реших да споделя опита си, в случай че помогне на някой друг. Ето последната диаграма с окончателното решение. Освен това има много код, който не съм добавил тук, но исках да го запазя прост и да подчертая колко страхотен е hookState за общността! Ето и окончателната диаграма на компонентите с функциите.