lets understand what's going on under the hood of emoji-picker-react by @ealush a meta software developer.
link to emoji-picker-react
here's his website
(this is not how to use emoji-picker-react but what going on inside)
now straight to the repository, the library makes use of custom hooks and React.context very extensively and a BIG emphasis on that, its like one contextProvider after another and then another and then another, it keeps on going.
The App structure (not the folder structure)
It lifts all the necessary state, ref, and config inside contexts, and wraps the whole ui content, which makes it easier to access anything, at any leaf component.
This is known as the [Provider pattern]
(https://www.patterns.dev/vanilla/provider-pattern/), which prevents passing props down multiple layers, and use using them wherever required.
The Component accepts props with callbacks such as
onEmojiClick: (e)=>{},
onReactionClick:(e)=>{},
onSkinToneChange: (e)=>{},
previewConfig: {}
these are for the user to pass callback handler functions to use the output and react to callbacks and also configs for the picker.
An intuitive way of open context api endpoints
, ( it's simple really, but for me, I haven't thought about passing them in this way)
Usually we create a Context, get all the values, build the state and create a simple :
const useMyContext = ()=> useContext(context)
The repository takes a different turn to exposing apis,
for Example
//usually we de-structure state right off the bat, but here its
//just an object that is passed to the provider and then used when
//accessed. (global states everywhere which only means, one end
//of your component can interact with another end without any
//problems)
const activeCategoryState = useState<ActiveCategoryState>(null);
const emojisThatFailedToLoadState = useState<Set<string>>(new Set());
const emojiVariationPickerState = useState<DataEmoji | null>(null);
<PickerContext.Provider
value={{
activeCategoryState,
emojiVariationPickerState,
emojisThatFailedToLoadState,
...
}}
>
{children}
</PickerContext.Provider>
//and then create a separate useContextHook for each, ( This is
//more expressive, modular, and easier to follow — especially
//when you're working with multiple context values -chatgpt. will
//update this once I get to the root why it's this way)
export function useEmojisThatFailedToLoadState() {
const { emojisThatFailedToLoadState } = React.useContext(PickerContext);
return emojisThatFailedToLoadState;
}
export function useIsPastInitialLoad(): boolean {
const { isPastInitialLoad } = React.useContext(PickerContext);
return isPastInitialLoad;
}
export function useEmojiVariationPickerState() {
const { emojiVariationPickerState } = React.useContext(PickerContext);
return emojiVariationPickerState;
}

//these are then later used to setVal or use val where //required
Events
Events are absolutely critical to any UI component,
whether its keyboard events, auto closing modals or focusing inputs, better interactivity is what make a good user experience
Emoji picker stitches event listeners with custom hooks and the context state used from the context apis to the component as the component loads the eventListeners are active.
(not the most beautiful diagrammer am I)
For example
export function useOnFocus() {
const BodyRef = useBodyRef();
const emojiStyle = useEmojiStyleConfig();
const getEmojiUrl = useGetEmojiUrlConfig();
useEffect(() => {
if (emojiStyle === EmojiStyle.NATIVE) {
return;
}
const bodyRef = BodyRef.current;
bodyRef?.addEventListener('focusin', onFocus);
return () => {
bodyRef?.removeEventListener('focusin', onFocus);
};
function onFocus(event: FocusEvent) {
//do stuff
}
}, [BodyRef, emojiStyle, getEmojiUrl]);
}
function PickerRootElement({ children }: RootProps) {
const [reactionsMode] = useReactionsModeState();
const theme = useThemeConfig();
...
useKeyboardNavigation();
useOnFocus();
return <div>...</div>
Emoji-picker-react by @ealush is a great example of implementing contextApi in a way how it's meant to be used,
Applying separation of concerns and preventing hectic prop passing everywhere, and using react properly.
This has been a great learning, also in the future I will be doing more under the hood implementations of react libraries, as I get good at it ofcourse.
Top comments (0)