Коллеги со стороны бакэнда иногда любезно спрашивают: "а нафига вам тут реакт"? Будем честны и ответим, что без него можно написать довольно приличный код, отдать его на ревью коллеге-фулстеку и получить аппрув после 15 секунд (так быстро не потому, что коллега не беспокоится за качество кода, а просто код весьма компактен, cмотрите ниже). Если подумать чуть-чуть дольше (например, за время заварки чая, которое, как все знают, равно трем минутам), можно найти не менее шести ошибок, а может и больше. Любая ошибка, конечно, весьма субъективна, но я постараюсь объективно объяснить каждую из них.
Ниже код представляет собой обычный список с кнопкой "добавить", код рабочий в том смысле, что его можно скопировать в файл и открыть в браузере.
<body>
<script>
class Component {
constructor(
container,
callback, // callback on add
emails = [], // state
) {
this.container = container;
this.callback = callback;
this.emails = emails;
}
templateForOneEmail(title, body) {
return `
<h4>${title}</h4>
<div>${body}</div>
<hr />
`;
}
template() {
const str = this.emails
.map(([title, body]) => this.templateForOneEmail(title, body))
.join("");
return `
<div id="my-emails">${str}</div>
<button id="my-button">Add</button>
`;
}
subscribe() {
const node = this.container.querySelector("#my-button");
if (node)
node.addEventListener("click", this.callback);
}
unsubscribe() {
const node = this.container.querySelector("#my-button");
if (node)
node.removeEventListener("click", this.callback);
}
render() {
this.unsubscribe();
this.container.innerHTML = this.template();
this.subscribe();
}
clear() {
this.unsubscribe();
this.container.innerHTML = "";
}
}
function main() {
const container = document.createElement("div");
document.body.appendChild(container);
const emails = [];
let comp = null;
const callback = () => {
if (!comp) { return; }
emails.push(["title", "body"]);
comp.clear();
comp = new Component(container, callback, emails);
comp.render();
}
comp = new Component(container, callback, emails);
comp.render();
}
main();
</script>
</body>
Итак, ошибки:
Начнем, пожалуй, с самой безобидной - Array.join в методе template. Вот, не свойство компонента конвертировать между массивом и строкой для рендинга. [jsx]
Перерисовка всего экрана при добавлении элемента. Интуитивно хочется дорисовать, а не перерисовать :) [virtual dom]
Вынужденные неточности с подписками - вызов unsubscribe (ресурсный метод) то тут, то там. Можно возразить, что в данном примере unsubscribe в рендере не нужен, так как мы можем вызвать clear следом, но в этом случае мы, к сожалению, теряем idempotence рендера (см. плиз https://en.wikipedia.org/wiki/Idempotence) [lifecycle]
Ссылка на самих себя в колбеке. Тут хороший вопрос, насколько это плохо для движка V8, но интуитивно создание цикла из ссылок не очень хорошая идея. [тут тег, в котором реакт не одобряет такое]
Создание компонента на каждый колбэк. Тут, возможно, и нет ничего плохого, но данное действие, скорее, увеличивает энтропию (о понимании программы) в целом, чем уменьшает ее. [state observers]
Ручная чистка ресурсов (метод clear нужно вызывать извне), как следствие, легко что-то забыть или потерять. [ownership]
И напоследок, вопрос о композиции таких компонентов - но это, как и на самом среднем проекте, обычно думается потом.