Communicating with Legacy: How JQuery and React Coexist

The term “legacy,” as defined in the Naver English Dictionary, encompasses both the remnants of a deceased individual and the enduring artifacts of the past. In the realm of coding, yesterday’s creations often swiftly transform into today’s legacy code.

The focus of this article is not solely on code that has withstood the passage of time. Instead, we delve into goormIDE’s jQuery code, which has weathered 6-7 years, remains distinct from contemporary technology stacks, and has yet to undergo any significant refactoring.

Despite its longevity, the jQuery code embedded within the service has persisted, albeit not without its share of challenges.

  1. My current team members, myself included, possess limited experience with jQuery.
  2. Certain actions’ methods are deeply entrenched and challenging to uncover.
  3. The absence of test code leaves us uncertain about potential side effects resulting from modifications.

To address this challenge, we embarked on a process of refactoring, migrating the jQuery codebase to React and JavaScript. However, progress was sluggish, and upon completion of the refactoring, customer perception remained unchanged, indicating a lack of tangible improvement in the product’s functionality.

Recognizing the urgency of the situation, we couldn’t afford to wait idly for the refactoring efforts to yield results. In tandem with refactoring, we initiated concurrent efforts to overhaul the UI/UX. This necessitated finding a method for harmonizing the coexistence of jQuery and React.

This article delves into two strategies for facilitating communication and coexistence between jQuery and React. Specifically, it explores the implementation of custom events and the transformation of modal creation methodologies. Let me elucidate how these disparate technology stacks successfully converged.

written by wynter
edit by snow

Utilize custom events for communication purposes.

자바스크립트(JavaScript, 이하 JS)에는 이벤트라는 개념이 있습니다. mdn은 ‘이벤트’란 개념을 다음과 같이 소개합니다.

Events are things that happen in the system you are programming, which the system tells you about so your code can react to them.

Events encompass mouse events, key events, and form events, with notable event types such as click, keydown, and focus. Apart from the events supplied by JS, users have the ability to generate their own events, termed ‘custom events’.

Initially, register the event listener as follows: Given our reliance on methods from legacy code, event registration occurs within the legacy codebase.

window.addEventListener('드래그시작', () => {
	document.querySelectorAll('.drag-ui').forEach((dragElement) => {
		const dropHelperEl = self.createDropHelper();
		dragElement.insertBefore(dropHelperEl, dragElement.firstChild);
  })
})

The code for event occurrence is as follows:

const dragStart = () => {
	// ...
	window.dispatchEvent(new CustomEvent('드래그시작'));
}

What are the advantages of employing custom events? Refactoring, as conducted thus far, necessitates extensive code modifications. While not all legacy logic has been migrated, its accumulation has reached a point where thorough review poses challenges.

<Figure> Commit count due to refactoring

The benefit of custom events lies in their ability to circumvent the need for relocating or replacing legacy code. In instances where the legacy system is too complex to disentangle all interdependencies, custom events enable the judicious reuse of existing logic. By leveraging pre-existing logic, concerns regarding potential side effects are mitigated.

However, the drawback is that the legacy logic persists, and the management of custom events becomes an additional responsibility.

Employ Redux events for communication purposes.

goormIDE utilizes Redux as its state management tool. However, the state managed within legacy code doesn’t automatically synchronize with the Redux store. By dispatching Redux events from legacy code, you can synchronize the state across your React components.

While employing Redux events in this manner, an idea struck me. “If Redux is responsible for managing modal state, could we exclusively utilize React to create new modals?” For instance, imagine needing to open a modal by selecting a specific menu item, but that functionality is currently implemented in jQuery.

In the past, modals were created or modified using jQuery code. However, now that I’m controlling modal state with Redux, triggering a Redux event in my jQuery code causes the modal to appear, as follows:

reduxStore.dispatch({
		type: 'modal/open',
		payload: {
			type: 'DeleteConfirmModal',
			props: {
				filePaths,
			},
		},
	});

In React, we manage it as follows:

// ModalManager.jsx
// ...
function ModalManager({ openedModal }) {
	if (!openedModal) return null;
	const modalType = modalIndex[openedModal.type];
	const modalComponent = modalType.component;
	const modalFunction = modalType.props;

	return (
		<ModalBoundary>
			<ModalComponent {...modalFunction} />
		</ModalBoundary>
	);
}

const mapStateToProps = (state) => ({
	openedModal: state.modal.opened,
})

// useModal.jsx
// ...
function useModal(type) {
	const dispatch = useDispatch();

	const opened = useSelector(state => state.modal.opened);
	const isOpen = opened?.type === type;
	
	const openModal = payload => dispatch(open(payload));
	const closeModal = payload => dispatch(close(payload));

	return { isOpen, openModal, closeModal };
}

Export all modals in a file named modalIndex. When a modal name is appended to the opened state controlled by Redux, ModalManager renders the modal. To trigger the opening of a modal in React, you can employ the useModal hook to declaratively open the modal, such as openModal(‘modal name’).

finish

I considered it worthwhile to share this concept in a post at some point, particularly after refining the modal handling approach. When I initially developed the code to coexist with legacy systems back in February 2022, I was relatively new to the field, having only two months of experience. Consequently, I hesitated to deem it a ‘good approach’. Resources on declarative modal management were scarce at the time, prompting extensive deliberation on my part. Now, similar modal management examples are readily available, a testament to the evolution of resources in the field. Here’s to the past version of myself, who diligently devised and grappled with this method.

The modal management technique overhauled two years ago has proven to be robust and trouble-free. It fills me with pride whenever my colleagues commend its ease of use.

Throughout the development of this method, my fervent wish was for the code I crafted not to become another legacy burden. Yet, inevitably, the code I authored will one day become part of someone else’s legacy. With that, I conclude the narrative of my interaction with legacy systems at that time, hopeful that someone else will adeptly elucidate my legacy in the future.

Posted by
snow cho

I'm the DevRel Manager at goorm Inc. I oversee COMMIT and our technical blog. I believe in transforming the development culture, akin to how snow blankets and melts away the world, and strive to improve it. Recently, I've been in the trenches seeking contributors and speakers for our technical blog.