mirror of
https://github.com/status-im/rn-emoji-keyboard.git
synced 2025-01-27 00:29:04 +00:00
refactor: optimization
This commit is contained in:
parent
f6f9d40647
commit
64f0d5afb3
@ -7,10 +7,11 @@ import {
|
||||
useWindowDimensions,
|
||||
Animated,
|
||||
} from 'react-native';
|
||||
import { CATEGORIES, CategoryTypes } from './types';
|
||||
import type { CategoryTypes, EmojisByCategory } from './types';
|
||||
import { EmojiCategory } from './components/EmojiCategory';
|
||||
import { KeyboardContext } from './KeyboardContext';
|
||||
import { Categories } from './components/Categories';
|
||||
import emojisByGroup from './assets/data-by-group.json';
|
||||
|
||||
export const EmojiKeyboard = () => {
|
||||
const { width } = useWindowDimensions();
|
||||
@ -18,7 +19,6 @@ export const EmojiKeyboard = () => {
|
||||
|
||||
const flatListRef = React.useRef<FlatList>(null);
|
||||
|
||||
// const scrollX = React.useRef(new Animated.Value(0)).current;
|
||||
const scrollNav = React.useRef(new Animated.Value(0)).current;
|
||||
|
||||
const getItemLayout = (
|
||||
@ -34,24 +34,6 @@ export const EmojiKeyboard = () => {
|
||||
(props) => <EmojiCategory {...props} />,
|
||||
[]
|
||||
);
|
||||
// const onScroll = Animated.event(
|
||||
// [{ nativeEvent: { contentOffset: { x: scrollX } } }],
|
||||
// {
|
||||
// listener: ({
|
||||
// nativeEvent: {
|
||||
// contentOffset: { x },
|
||||
// },
|
||||
// }: NativeSyntheticEvent<NativeScrollEvent>) => {
|
||||
// console.log(Math.round(x / width));
|
||||
// ctx.setActiveCategoryIndex(Math.round(x / width));
|
||||
// // Animated.spring(scrollNav, {
|
||||
// // toValue: (x / width) * (28 + 9),
|
||||
// // useNativeDriver: true,
|
||||
// // }).start();
|
||||
// },
|
||||
// useNativeDriver: true,
|
||||
// }
|
||||
// );
|
||||
React.useEffect(() => {
|
||||
Animated.spring(scrollNav, {
|
||||
toValue: ctx.activeCategoryIndex * (28 + 9),
|
||||
@ -64,8 +46,8 @@ export const EmojiKeyboard = () => {
|
||||
style={[styles.container, styles.containerShadow, ctx.containerStyles]}
|
||||
>
|
||||
<Animated.FlatList
|
||||
data={CATEGORIES}
|
||||
keyExtractor={(item: CategoryTypes) => item}
|
||||
data={emojisByGroup}
|
||||
keyExtractor={(item: EmojisByCategory) => item.title}
|
||||
renderItem={renderItem}
|
||||
removeClippedSubviews={true}
|
||||
ref={flatListRef}
|
||||
@ -74,12 +56,10 @@ export const EmojiKeyboard = () => {
|
||||
showsHorizontalScrollIndicator={false}
|
||||
pagingEnabled
|
||||
scrollEventThrottle={16}
|
||||
decelerationRate="fast"
|
||||
getItemLayout={getItemLayout}
|
||||
scrollEnabled={false}
|
||||
// onScroll={onScroll}
|
||||
initialNumToRender={1}
|
||||
windowSize={1}
|
||||
windowSize={2}
|
||||
maxToRenderPerBatch={1}
|
||||
/>
|
||||
<Categories flatListRef={flatListRef} scrollNav={scrollNav} />
|
||||
|
@ -24,6 +24,7 @@ export type ContextValues = {
|
||||
activeCategoryIndex: number;
|
||||
setActiveCategoryIndex: (index: number) => void;
|
||||
numberOfColumns: number;
|
||||
width: number;
|
||||
};
|
||||
|
||||
export const KeyboardContext = React.createContext<
|
||||
|
@ -1,4 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { useWindowDimensions } from 'react-native';
|
||||
import {
|
||||
KeyboardProps,
|
||||
ContextValues,
|
||||
@ -29,11 +30,21 @@ export const defaultKeyboardValues: ContextValues = {
|
||||
activeCategoryIndex: 0,
|
||||
setActiveCategoryIndex: () => {},
|
||||
numberOfColumns: 5,
|
||||
width: 0,
|
||||
};
|
||||
|
||||
export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
|
||||
const { width } = useWindowDimensions();
|
||||
const [activeCategoryIndex, setActiveCategoryIndex] = React.useState(0);
|
||||
|
||||
const numberOfColumns = React.useRef<number>(
|
||||
Math.floor(
|
||||
width /
|
||||
((props.emojiSize
|
||||
? props.emojiSize
|
||||
: defaultKeyboardContext.emojiSize) *
|
||||
2)
|
||||
)
|
||||
);
|
||||
React.useEffect(() => {
|
||||
if (props.open) setActiveCategoryIndex(0);
|
||||
}, [props.open]);
|
||||
@ -44,6 +55,8 @@ export const KeyboardProvider: React.FC<ProviderProps> = React.memo((props) => {
|
||||
...props,
|
||||
activeCategoryIndex,
|
||||
setActiveCategoryIndex,
|
||||
numberOfColumns: numberOfColumns.current,
|
||||
width,
|
||||
};
|
||||
return (
|
||||
<KeyboardContext.Provider value={value}>
|
||||
|
9072
src/assets/data-by-group.json
Normal file
9072
src/assets/data-by-group.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,7 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
FlatList,
|
||||
useWindowDimensions,
|
||||
} from 'react-native';
|
||||
import emojisByGroup from 'unicode-emoji-json/data-by-group.json';
|
||||
import type { CategoryTypes, EmojiType } from 'src/types';
|
||||
import { StyleSheet, View, Text, FlatList } from 'react-native';
|
||||
import type { EmojisByCategory, EmojiType } from 'src/types';
|
||||
import { SingleEmoji } from './SingleEmoji';
|
||||
import { KeyboardContext } from '../KeyboardContext';
|
||||
|
||||
@ -21,25 +14,24 @@ const emptyEmoji = {
|
||||
emoji_version: '0',
|
||||
};
|
||||
|
||||
export const EmojiCategory = ({ item }: { item: CategoryTypes }) => {
|
||||
const { width } = useWindowDimensions();
|
||||
const ctx = React.useContext(KeyboardContext);
|
||||
const numberOfColumns = React.useRef<number>(
|
||||
Math.floor(width / (ctx.emojiSize * 2))
|
||||
);
|
||||
export const EmojiCategory = ({ item }: { item: EmojisByCategory }) => {
|
||||
const { onEmojiSelected, emojiSize, ...ctx } =
|
||||
React.useContext(KeyboardContext);
|
||||
|
||||
const [empty, setEmpty] = React.useState<EmojiType[]>([]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const fillWithEmpty = new Array(
|
||||
numberOfColumns.current -
|
||||
(emojisByGroup[item].length % numberOfColumns.current)
|
||||
).fill(emptyEmoji);
|
||||
setEmpty(fillWithEmpty);
|
||||
}, [item]);
|
||||
if (item.data.length % ctx.numberOfColumns) {
|
||||
const fillWithEmpty = new Array(
|
||||
ctx.numberOfColumns - (item.data.length % ctx.numberOfColumns)
|
||||
).fill(emptyEmoji);
|
||||
setEmpty(fillWithEmpty);
|
||||
}
|
||||
}, [ctx.numberOfColumns, item]);
|
||||
|
||||
const getItemLayout = (_: EmojiType[] | null | undefined, index: number) => ({
|
||||
length: ctx.emojiSize ? ctx.emojiSize : 0,
|
||||
offset: ctx.emojiSize * Math.ceil(index / ctx.numberOfColumns),
|
||||
length: emojiSize ? emojiSize : 0,
|
||||
offset: emojiSize * Math.ceil(index / ctx.numberOfColumns),
|
||||
index,
|
||||
});
|
||||
|
||||
@ -47,26 +39,29 @@ export const EmojiCategory = ({ item }: { item: CategoryTypes }) => {
|
||||
(props) => (
|
||||
<SingleEmoji
|
||||
{...props}
|
||||
onPress={() => ctx.onEmojiSelected(props.item)}
|
||||
emojiSize={ctx.emojiSize}
|
||||
onPress={() => onEmojiSelected(props.item)}
|
||||
emojiSize={emojiSize}
|
||||
/>
|
||||
),
|
||||
[ctx]
|
||||
[onEmojiSelected, emojiSize]
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { width: width }]}>
|
||||
<View style={[styles.container, { width: ctx.width }]}>
|
||||
{!ctx.hideHeader && (
|
||||
<Text style={[styles.sectionTitle, ctx.headerStyles]}>{item}</Text>
|
||||
<Text style={[styles.sectionTitle, ctx.headerStyles]}>
|
||||
{item.title}
|
||||
</Text>
|
||||
)}
|
||||
<FlatList
|
||||
data={[...emojisByGroup[item], ...empty]}
|
||||
data={[...item.data, ...empty]}
|
||||
keyExtractor={(emoji) => emoji.name}
|
||||
numColumns={numberOfColumns.current}
|
||||
numColumns={ctx.numberOfColumns}
|
||||
renderItem={renderItem}
|
||||
removeClippedSubviews={true}
|
||||
getItemLayout={getItemLayout}
|
||||
ListFooterComponent={() => <View style={styles.footer} />}
|
||||
windowSize={1}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
@ -58,3 +58,8 @@ export const CATEGORIES_NAVIGATION: CategoryNavigationItem[] = [
|
||||
// { icon: '🏧', category: 'Symbols' },
|
||||
// { icon: '🏁', category: 'Flags' },
|
||||
// ];
|
||||
|
||||
export type EmojisByCategory = {
|
||||
title: CategoryTypes;
|
||||
data: EmojiType[];
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user