Рефакторинг через классы: вычищаем свой JavaScript-код
Перевод статьи «JavaScript code cleanup: how you can refactor to use Classes»
Иван Капцов
В небольших React-проектах достаточно эффективно хранить все методы компонентов в самих компонентах. В проектах среднего размера вам может понадобиться сделать из метода компонента вспомогательную функцию. В этом случае можно использовать классы (вместо экспорта отдельных функций и переменных).
Обычный рефакторинг
В обычном рефакторинге вы берёте функцию для компонента и выносите её в другой файл.
Из:
const MyComponent = () => { const someFunction = () => 'Hey, I am text' return ( <div> {someFunction()} </div>> ) }
В:
import { someFunction } from 'functionHelper.js' const MyComponent = () => { return ( <div> {someFunction()} </div> ) }
И
export const someFunction = () => 'Hey, I am text'
Это простой пример, но суть подхода ясна:
- Вынести функции в отдельный файл.
- Импортировать их в другой и вызывать как обычно.
Когда программа становится сложнее, вам приходится передавать много разных параметров — объекты, функции для управления состоянием и так далее. В итоге можно столкнуться с проблемой, когда нужно извлечь из компонента три функции, каждая из которых требует одинаковых входных данных (resource
и функция для обновления resource
). В таком случае разумно будет выносить эту функциональность в классы.
Рефакторинг через классы
Для того, чтобы понять этот подход, посмотрите на репозиторий, созданный специально для этого материала.
Фрагмент демо
Первоначальный коммит выполняет всю функциональность внутри основного компонента (App.js), а последующие коммиты рефакторят код для использования классов.
Вы можете запустить демо сами. Не забудьте выполнить yarn install
.
Frontend developer (Vue)
Sportmaster Lab, Липецк, до 130 000 ₽
tproger.ru Вакансии на tproger.ru
Мы начнём с компонента, который «получает» объект (имитируя способ, которым мы могли бы сделать это через API) с определёнными атрибутами: repeat
(количество блоков), side
(height
and width
), text
, color
. У нас есть несколько способов управления видом — изменение цвета, обновление текста и так далее. После каждого изменения мы показываем сообщение.
Например, вот метод изменения ширины и высоты:
changeSide = side => { const obj = {...this.state.obj, side} this.fetchObject(obj); this.setState({ message: `You changed the sides to ${side} pixels!` }); }
Если у нас есть несколько схожих методов, то придётся много раз передавать одни и те же параметры, что не очень удобно (и читабельно).
Вместо передачи большого числа параметров мы можем использовать класс с конструктором:
export default class ObjectManipulator { constructor( { object, fetchObject, markResettable, updateMessage, updateStateValue } ) { this.fetchObject = fetchObject; this.markResettable = markResettable; this.updateMessage = updateMessage; this.updateStateValue = updateStateValue; } changeSide = ( object, side ) => { const newObject = { ...object, side }; this.fetchObject(newObject); this.updateMessage(`You changed the sides to ${side} pixels!`); this.markResettable(); this.updateStateValue('side', side); }; };
Такой метод позволяет нам создать объект, функции которого можно вызвать внутри основного компонента:
const manipulator = new ObjectManipulator({ object, fetchObject: this.fetchObject, markResettable: this.markResettable, updateMessage: this.updateMessage, updateStateValue: this.updateStateValue, });
Здесь создаётся объект manipulator
— экземпляр нашего класса ObjectManipulator
. Когда мы вызываем manipulator.changeSide(object, '800')
, он запускает метод changeSide
, который мы определили выше. Нет необходимости передавать updateMessage
или любой другой метод — мы уже передали их в конструкторе.
Этот способ становится полезным, если мы используем много методов. В нашем случае нужно было вызывать .then (res => myFunction (res)
после всего, что пытались извлечь. Теперь не нужно писать лишний код благодаря определению в экземпляре класса.
Держать всё на своих местах
Следующий приём организации кода может быть очень полезен, чтобы держать всё на своих местах. Например, есть константный массив цветов, к которым применяется функция map()
, чтобы получились цветные кнопки, которые вы видите в демо. Перемещая эту константу в ObjectManipulator
, можно убедиться, что она не конфликтует с другими переменными colors
в приложении:
export default class ObjectManipulator { [...] colors = ['blue', 'red', 'orange', 'aquamarine', 'green', 'gray', 'magenta']; };
Таким образом можно использовать manipulator.colors
, чтобы получить правильные цвета для страницы, сохранив глобальную константу colors
для чего-то другого.
В итоге мы почистили код, сделали его понятней и читабельней.
React: практики, которые помогут стать продвинутым разработчикомtproger.ru
Хинт для программистов: если зарегистрируетесь на соревнования Huawei Honor Cup, бесплатно получите доступ к онлайн-школе для участников. Можно прокачаться по разным навыкам и выиграть призы в самом соревновании.
Перейти к регистрации
- 19 views
- 0 Comment