Pull to refresh

Используем React: эксклюзивная лечебная методика сидения на трёх стульях сразу

Где болит


Как давно подмечено — легко в теории, хаос на практике. Несмотря на использование архитектурных шаблонов, типа Flux, Reflux, Redux, реальная жизнь (если только задача вашего кода несколько больше, чем «Hello World!») гарантирует ситуацию, когда код ваших React-компонентов может вырасти до размеров, несовместимых с лёгкостью чтения и осмысления. Как часто среди переопределённых методов жизненного цикла громоздятся либо дополнительные функции обработчиков разнообразных кликов, либо вспомогательная функциональность, решающая что рендерить в том или ином случае, либо всё сразу и.д. и т.п. И вот если Вы достигли данного состояния сложности бытия, то возникает закономерный вопрос: как отрефакторить всю получившуюся кучу гов..., простите, кода, в нечто приятное глазу и пониманию.

Как лечить


На основе личной практики предлагаю модель расчленёнки: Model-Component-View (MCV). Вашему вниманию предлагается принцип разделения кода компонента на три части согласно взгляда на стандартный реакт-компонент в трёх аспектах: данные, инфраструктура самого реакта, пользовательский интерфейс. В результате такой формализации из одного реакт-компонента получим три модуля (класса):

  • Model — подобна ModelView из паттерна MVVM — сюда мы выносим код определяющий отношения нашего компонента с окружающим его миром — прежде всего логика отображения данных (в этом модуле возможна завязка на архитектурные подходы типа Flux).
  • Component — собственно компонент (такой весь зачатый от React.Component) с его сложным жизненным циклом и жизненным путём и даже с рендером..., но без разметки. А вот о ней заботится следующий элемент:
  • View — здесь собственно разметка, ну и задача данного модуля — представление (и только представление!) данных получаемых от модели.

Особо хочу подчеркнуть, что данный подход никак не конфликтует с известными архитектурными подходами используемыми в React, поскольку лежит вне их пределов — он о другом. Он о том, по каким принципам и как производить декомпозицию самих компонентов (для чего — смотри главу «где болит»).

Применение и дозировка


В случае небольшого кол-ва переопределённых методов жизненного цикла, наличия одного обработчика onClick и куцей разметки применять НЕ РЕКОМЕНДУЕТСЯ.

Терапевтический эффект


Улучшение стуктурированности кода на фоне декомпозиции.

Анатомический театр


Ну и не как рецепт, а в качестве руководства к действию немножко демонстрации предлагаемого подхода (пример, естественно, упрощённый):

//Собственно компонент - здесь только стадии жизненного цикла и ничего более.
class Order extends React.Component{

	constructor(props){
		super(props);
		this.state = {orderStruct: props.orderData};
	}
	
	componentWillReceiveProps(nextProps){
		this.setState({orderStruct: (nextProps).orderData});
	}
	
	render(){
		new OrderModel(this);
		new OrderView(this.model);
		return this.view.render();
	}
}


//Модель отображения - здесь мы определяем, что и как должно заполнять нашу разметку
class OrderModel{

	constructor(component){	
		//устанавливаем в компоненте ссылку на модель
		component.model = this;		
		this.component = component;
	}

	get orderStruct(){
		return this.component.state.orderStruct;
	}

	//Свойства и методы для	отображения атрибутов заказа ------------
	get orderTitle(){
		try{
			return 'Заказ на обслуживание № ' + this.orderStruct.orderNumber;
		}
		catch{
			return 'Данные отсутствуют';
		}
	}	
	...............................
	//Обработчики событий и т.п. ---------------
	handleResetStatusButtonClick(){
		//Обращение к гипотетическому диспетчеру (в рамках данного примера не рассматривается) 
		//для вызова действия обновления статуса заказа
		var dispatcher = new Dispatcher();
		dispatcher.callAction('ResetOrderStatus', this.component.refs.statusCtrl.status);
	}		
}

//Представление - только вывод.
class OrderView{

	constructor(model){
		this.model = model;
	}

	render(){
		return <div>
			<OrderTitle caption={this.model.orderTitle}>
			.......................
			.......................
			.......................
			.......................
			.......................
			<OrderStatusControl status={this.model.status} ref="statusCtrl" />
			<ResetStatusButton caption="Обновить статус" onClick={this.model.handleResetStatusButtonClick} />
		</div>
	}
}
Tags:
Hubs:
You can’t comment this publication because its author is not yet a full member of the community. You will be able to contact the author only after he or she has been invited by someone in the community. Until then, author’s username will be hidden by an alias.