Коллеги со стороны бакэнда иногда любезно спрашивают: "а нафига вам тут реакт"? Будем честны и ответим, что без него можно написать довольно приличный код, отдать его на ревью коллеге-фулстеку и получить аппрув после 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]
И напоследок, вопрос о композиции таких компонентов - но это, как и на самом среднем проекте, обычно думается потом.