# React

### UseEffect

{% embed url="<https://reactjs.org/docs/hooks-effect.html>" %}

### ReactNodes

You can add components as props to work them into the layout of another component. Here is an example from the project.

{% code title="gravity/frontend/components/blocks/promotions/PromotionsBlock.tsx" %}

```tsx
{/* BACKEND RENDER */}
{isEditing && (
	<div className="flex flex-wrap mb-12">
		{promotionsList?.map((promotion) => (
			...
		))}
		{editorControls}
	</div>
)}
```

{% endcode %}

Here we add the `editorControls` to the backend render.

{% code title="gravity/backend/plugins/gravity-platform-core/src/blocks/promotions/edit.tsx" %}

```tsx
editorControls={
	<>
		{availablePromotions?.length > 0 && (
			<Listbox value={selected} onChange={setSelected}>
				<div className="relative mt-5 lg:w-1/4">
					<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-white rounded-lg shadow-md cursor-default focus:outline-none focus-visible:ring-2 focus-visible:ring-opacity-75 focus-visible:ring-white focus-visible:ring-offset-orange-300 focus-visible:ring-offset-2 focus-visible:border-indigo-500 sm:text-sm">
						<span className="block truncate">Add Promotion</span>
						<span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
							<HiOutlinePlusCircle
								className="w-5 h-5 text-gray-400"
								aria-hidden="true"
							/>
						</span>
					</Listbox.Button>
					<Transition
						as={Fragment}
						leave="transition ease-in duration-100"
						leaveFrom="opacity-100"
						leaveTo="opacity-0"
					>
						<Listbox.Options className="absolute w-full py-1 mt-1 overflow-auto text-base bg-white rounded-md shadow-lg max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
							{availablePromotions?.map((promo) => (
								<Listbox.Option
									key={promo.id}
									className={({ active }) =>
										`${
											active
												? "text-amber-900 bg-amber-100"
												: "text-gray-900"
										}
                              cursor-default select-none relative py-2 pl-3 pr-4`
									}
									value={promo.id}
								>
									{({ selected }) => (
										<>
											<span
												className={`${
													selected ? "font-medium" : "font-bold"
												} block truncate`}
											>
												{promo.title.rendered}
											</span>
										</>
									)}
								</Listbox.Option>
							))}
						</Listbox.Options>
					</Transition>
				</div>
			</Listbox>
		)}
	</>
}
```

{% endcode %}

We can pass this whole component and it's render logic as a prop. This allows us to fit it into the layout of the display component.

![](https://2634576350-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MihuyQ2hRhMOkQuQosr%2Fuploads%2FWxyrq0477LnNmqqvDUvX%2Fimage.png?alt=media\&token=e70e6c03-19b3-49e2-a744-72c0ead99d93)

### Converting Ids to Actual Objects

{% code title="frontend/components/blocks/promotions/PromotionsBlock.tsx" %}

```tsx
const promotionsList = (
	selectedPromotionIds?.length
		? selectedPromotionIds
				?.map((id) =>
					promotions.find((promotion) => promotion.databaseId === id)
				)
				.filter((p) => p)
		: promotions
) as IPromotion[];
```

{% endcode %}

Here we map the IDs to the objects they represent. The final filter is to be sure that none of those are null.
