Performance improvements on Home to Channel (#6106)
This commit is contained in:
parent
9069048aa7
commit
328f029a93
16 changed files with 117 additions and 46 deletions
|
|
@ -152,7 +152,9 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const emptyList: UserProfile[] = [];
|
||||
const emptyProfileList: UserProfile[] = [];
|
||||
const empytSectionList: UserMentionSections = [];
|
||||
const emptyGroupList: Group[] = [];
|
||||
|
||||
const AtMention = ({
|
||||
channelId,
|
||||
|
|
@ -170,20 +172,20 @@ const AtMention = ({
|
|||
const theme = useTheme();
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
const [sections, setSections] = useState<UserMentionSections>([]);
|
||||
const [usersInChannel, setUsersInChannel] = useState<UserProfile[]>([]);
|
||||
const [usersOutOfChannel, setUsersOutOfChannel] = useState<UserProfile[]>([]);
|
||||
const [groups, setGroups] = useState<Group[]>([]);
|
||||
const [sections, setSections] = useState<UserMentionSections>(empytSectionList);
|
||||
const [usersInChannel, setUsersInChannel] = useState<UserProfile[]>(emptyProfileList);
|
||||
const [usersOutOfChannel, setUsersOutOfChannel] = useState<UserProfile[]>(emptyProfileList);
|
||||
const [groups, setGroups] = useState<Group[]>(emptyGroupList);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [noResultsTerm, setNoResultsTerm] = useState<string|null>(null);
|
||||
const [localCursorPosition, setLocalCursorPosition] = useState(cursorPosition); // To avoid errors due to delay between value changes and cursor position changes.
|
||||
|
||||
const runSearch = useMemo(() => debounce(async (sUrl: string, term: string, cId?: string) => {
|
||||
setLoading(true);
|
||||
const {users: receivedUsers, error} = await searchUsers(sUrl, term, cId);
|
||||
if (!error) {
|
||||
setUsersInChannel(receivedUsers!.users);
|
||||
setUsersOutOfChannel(receivedUsers!.out_of_channel || emptyList);
|
||||
const {users: receivedUsers} = await searchUsers(sUrl, term, cId);
|
||||
if (receivedUsers) {
|
||||
setUsersInChannel(receivedUsers.users.length ? receivedUsers.users : emptyProfileList);
|
||||
setUsersOutOfChannel(receivedUsers.out_of_channel?.length ? receivedUsers.out_of_channel : emptyProfileList);
|
||||
}
|
||||
setLoading(false);
|
||||
}, 200), []);
|
||||
|
|
@ -195,9 +197,9 @@ const AtMention = ({
|
|||
|
||||
const matchTerm = getMatchTermForAtMention(value.substring(0, localCursorPosition), isSearch);
|
||||
const resetState = () => {
|
||||
setUsersInChannel(emptyList);
|
||||
setUsersOutOfChannel(emptyList);
|
||||
setSections([]);
|
||||
setUsersInChannel(emptyProfileList);
|
||||
setUsersOutOfChannel(emptyProfileList);
|
||||
setSections(empytSectionList);
|
||||
runSearch.cancel();
|
||||
};
|
||||
|
||||
|
|
@ -222,7 +224,7 @@ const AtMention = ({
|
|||
|
||||
onShowingChange(false);
|
||||
setNoResultsTerm(mention);
|
||||
setSections([]);
|
||||
setSections(empytSectionList);
|
||||
}, [value, localCursorPosition, isSearch]);
|
||||
|
||||
const renderSpecialMentions = useCallback((item: SpecialMention) => {
|
||||
|
|
@ -286,12 +288,12 @@ const AtMention = ({
|
|||
useEffect(() => {
|
||||
if (useGroupMentions) {
|
||||
getGroupsForAutocomplete(serverUrl, channelId || '').then((res) => {
|
||||
setGroups(res);
|
||||
setGroups(res.length ? res : emptyGroupList);
|
||||
}).catch(() => {
|
||||
setGroups([]);
|
||||
setGroups(emptyGroupList);
|
||||
});
|
||||
} else {
|
||||
setGroups([]);
|
||||
setGroups(emptyGroupList);
|
||||
}
|
||||
}, [channelId, useGroupMentions]);
|
||||
|
||||
|
|
@ -318,7 +320,7 @@ const AtMention = ({
|
|||
if (!loading && !nSections && noResultsTerm == null) {
|
||||
setNoResultsTerm(matchTerm);
|
||||
}
|
||||
setSections(newSections);
|
||||
setSections(nSections ? newSections : empytSectionList);
|
||||
onShowingChange(Boolean(nSections));
|
||||
}, [usersInChannel, usersOutOfChannel, teamMembers, groups, loading]);
|
||||
|
||||
|
|
|
|||
|
|
@ -161,6 +161,9 @@ const getStyleFromTheme = makeStyleSheetFromTheme((theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
const emptySections: Array<SectionListData<Channel>> = [];
|
||||
const emptyChannels: Channel[] = [];
|
||||
|
||||
const ChannelMention = ({
|
||||
cursorPosition,
|
||||
isSearch,
|
||||
|
|
@ -175,8 +178,8 @@ const ChannelMention = ({
|
|||
const theme = useTheme();
|
||||
const style = getStyleFromTheme(theme);
|
||||
|
||||
const [sections, setSections] = useState<Array<SectionListData<Channel>>>([]);
|
||||
const [channels, setChannels] = useState<Channel[]>([]);
|
||||
const [sections, setSections] = useState<Array<SectionListData<Channel>>>(emptySections);
|
||||
const [channels, setChannels] = useState<Channel[]>(emptyChannels);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [noResultsTerm, setNoResultsTerm] = useState<string|null>(null);
|
||||
const [localCursorPosition, setLocalCursorPosition] = useState(cursorPosition); // To avoid errors due to delay between value changes and cursor position changes.
|
||||
|
|
@ -187,17 +190,17 @@ const ChannelMention = ({
|
|||
|
||||
const runSearch = useMemo(() => debounce(async (sUrl: string, term: string) => {
|
||||
setLoading(true);
|
||||
const {channels: receivedChannels, error} = await searchChannels(sUrl, term);
|
||||
if (!error) {
|
||||
setChannels(receivedChannels!);
|
||||
const {channels: receivedChannels} = await searchChannels(sUrl, term);
|
||||
if (receivedChannels) {
|
||||
setChannels(receivedChannels.length ? receivedChannels : emptyChannels);
|
||||
}
|
||||
setLoading(false);
|
||||
}, 200), []);
|
||||
|
||||
const matchTerm = getMatchTermForChannelMention(value.substring(0, localCursorPosition), isSearch);
|
||||
const resetState = () => {
|
||||
setChannels([]);
|
||||
setSections([]);
|
||||
setChannels(emptyChannels);
|
||||
setSections(emptySections);
|
||||
runSearch.cancel();
|
||||
};
|
||||
|
||||
|
|
@ -235,7 +238,7 @@ const ChannelMention = ({
|
|||
|
||||
onShowingChange(false);
|
||||
setNoResultsTerm(mention);
|
||||
setSections([]);
|
||||
setSections(emptySections);
|
||||
}, [value, localCursorPosition, isSearch]);
|
||||
|
||||
const renderItem = useCallback(({item}) => {
|
||||
|
|
@ -286,7 +289,7 @@ const ChannelMention = ({
|
|||
if (!loading && !nSections && noResultsTerm == null) {
|
||||
setNoResultsTerm(matchTerm);
|
||||
}
|
||||
setSections(newSections);
|
||||
setSections(newSections.length ? newSections : emptySections);
|
||||
onShowingChange(Boolean(nSections));
|
||||
}, [channels, myMembers, loading]);
|
||||
|
||||
|
|
|
|||
|
|
@ -208,5 +208,5 @@ const Header = ({
|
|||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
export default React.memo(Header);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {combineLatest, of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
|
|
@ -42,4 +43,4 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
|||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(DraftHandler));
|
||||
export default React.memo(withDatabase(enhanced(DraftHandler)));
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {combineLatest, of as of$, from as from$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
|
|
@ -85,4 +86,4 @@ const enhanced = withObservables([], (ownProps: WithDatabaseArgs & OwnProps) =>
|
|||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(PostDraft));
|
||||
export default React.memo(withDatabase(enhanced(PostDraft)));
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
|
|
@ -59,4 +60,4 @@ const enhanced = withObservables([], ({database, channelId, rootId}: WithDatabas
|
|||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(PostInput));
|
||||
export default React.memo(withDatabase(enhanced(PostInput)));
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {combineLatest, of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
|
|
@ -35,4 +36,4 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => {
|
|||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(QuickActions));
|
||||
export default React.memo(withDatabase(enhanced(QuickActions)));
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
export default function Typing({
|
||||
function Typing({
|
||||
channelId,
|
||||
rootId,
|
||||
}: Props) {
|
||||
|
|
@ -155,3 +155,5 @@ export default function Typing({
|
|||
</Animated.View>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Typing);
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ const getStyleSheet = makeStyleSheetFromTheme((theme) => {
|
|||
};
|
||||
});
|
||||
|
||||
export default function Uploads({
|
||||
function Uploads({
|
||||
currentUserId,
|
||||
files,
|
||||
uploadFileError,
|
||||
|
|
@ -174,3 +174,5 @@ export default function Uploads({
|
|||
</GalleryInit>
|
||||
);
|
||||
}
|
||||
|
||||
export default React.memo(Uploads);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {combineLatest, from as from$, of as of$} from 'rxjs';
|
||||
import {map, switchMap} from 'rxjs/operators';
|
||||
|
||||
|
|
@ -54,4 +55,4 @@ const withCombinedPosts = withObservables(['postId'], ({database, postId}: WithD
|
|||
};
|
||||
});
|
||||
|
||||
export default withDatabase(withCombinedPosts(CombinedUserActivity));
|
||||
export default React.memo(withDatabase(withCombinedPosts(CombinedUserActivity)));
|
||||
|
|
|
|||
|
|
@ -68,6 +68,8 @@ const Reaction = ({count, emojiName, highlight, onPress, onLongPress, theme}: Re
|
|||
onPress(emojiName, highlight);
|
||||
}, [highlight]);
|
||||
|
||||
const fontStyle = useMemo(() => [styles.count, (highlight && styles.countHighlight)], [styles, highlight]);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
onPress={handlePress}
|
||||
|
|
@ -86,7 +88,7 @@ const Reaction = ({count, emojiName, highlight, onPress, onLongPress, theme}: Re
|
|||
<View style={styles.countContainer}>
|
||||
<AnimatedNumbers
|
||||
includeComma={false}
|
||||
fontStyle={[styles.count, (highlight && styles.countHighlight)]}
|
||||
fontStyle={fontStyle}
|
||||
animateToNumber={count}
|
||||
animationDuration={450}
|
||||
/>
|
||||
|
|
@ -95,4 +97,4 @@ const Reaction = ({count, emojiName, highlight, onPress, onLongPress, theme}: Re
|
|||
);
|
||||
};
|
||||
|
||||
export default Reaction;
|
||||
export default React.memo(Reaction);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import React, {useCallback, useRef, useState} from 'react';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {Keyboard, TouchableOpacity, View} from 'react-native';
|
||||
|
||||
|
|
@ -11,6 +11,7 @@ import {Screens} from '@constants';
|
|||
import {MAX_ALLOWED_REACTIONS} from '@constants/emoji';
|
||||
import {useServerUrl} from '@context/server';
|
||||
import {useIsTablet} from '@hooks/device';
|
||||
import useDidUpdate from '@hooks/did_update';
|
||||
import {bottomSheetModalOptions, showModal, showModalOverCurrentContext} from '@screens/navigation';
|
||||
import {getEmojiFirstAlias} from '@utils/emoji/helpers';
|
||||
import {preventDoubleTap} from '@utils/tap';
|
||||
|
|
@ -66,7 +67,7 @@ const Reactions = ({currentUserId, canAddReaction, canRemoveReaction, disabled,
|
|||
const [sortedReactions, setSortedReactions] = useState(new Set(reactions.map((r) => getEmojiFirstAlias(r.emojiName))));
|
||||
const styles = getStyleSheet(theme);
|
||||
|
||||
useEffect(() => {
|
||||
useDidUpdate(() => {
|
||||
// This helps keep the reactions in the same position at all times until unmounted
|
||||
const rs = reactions.map((r) => getEmojiFirstAlias(r.emojiName));
|
||||
const sorted = new Set([...sortedReactions]);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {from as from$, of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
||||
|
|
@ -141,4 +142,4 @@ const withPost = withObservables(
|
|||
};
|
||||
});
|
||||
|
||||
export default withDatabase(withSystem(withPost(Post)));
|
||||
export default React.memo(withDatabase(withSystem(withPost(Post))));
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
import {Q} from '@nozbe/watermelondb';
|
||||
import {withDatabase} from '@nozbe/watermelondb/DatabaseProvider';
|
||||
import withObservables from '@nozbe/with-observables';
|
||||
import React from 'react';
|
||||
import {AppStateStatus} from 'react-native';
|
||||
import {of as of$} from 'rxjs';
|
||||
import {switchMap} from 'rxjs/operators';
|
||||
|
|
@ -47,4 +48,4 @@ const enhanced = withObservables(['channelId', 'forceQueryAfterAppState'], ({dat
|
|||
};
|
||||
});
|
||||
|
||||
export default withDatabase(enhanced(ChannelPostList));
|
||||
export default React.memo(withDatabase(enhanced(ChannelPostList)));
|
||||
|
|
|
|||
63
package-lock.json
generated
63
package-lock.json
generated
|
|
@ -154,6 +154,7 @@
|
|||
"mock-async-storage": "2.2.0",
|
||||
"nock": "13.2.4",
|
||||
"patch-package": "6.4.7",
|
||||
"react-devtools-core": "4.24.3",
|
||||
"react-native-svg-transformer": "1.0.0",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"tough-cookie": "4.0.0",
|
||||
|
|
@ -19518,9 +19519,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/react-devtools-core": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.19.1.tgz",
|
||||
"integrity": "sha512-2wJiGffPWK0KggBjVwnTaAk+Z3MSxKInHmdzPTrBh1mAarexsa93Kw+WMX88+XjN+TtYgAiLe9xeTqcO5FfJTw==",
|
||||
"version": "4.24.3",
|
||||
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.3.tgz",
|
||||
"integrity": "sha512-+htKZxLxDN14jhRG3+IXRiJqNSGHUiPYrMtv9e7qlZxcbKeJjVs+C/hd8kZF5rydp3faBwFN6ZpTaZnLA3/ZGA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"shell-quote": "^1.6.1",
|
||||
"ws": "^7"
|
||||
|
|
@ -20224,6 +20226,35 @@
|
|||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native/node_modules/react-devtools-core": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.19.1.tgz",
|
||||
"integrity": "sha512-2wJiGffPWK0KggBjVwnTaAk+Z3MSxKInHmdzPTrBh1mAarexsa93Kw+WMX88+XjN+TtYgAiLe9xeTqcO5FfJTw==",
|
||||
"dependencies": {
|
||||
"shell-quote": "^1.6.1",
|
||||
"ws": "^7"
|
||||
}
|
||||
},
|
||||
"node_modules/react-native/node_modules/react-devtools-core/node_modules/ws": {
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
|
||||
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": "^5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/react-native/node_modules/react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
|
|
@ -24181,6 +24212,7 @@
|
|||
"version": "7.5.5",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
|
||||
"integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8.3.0"
|
||||
},
|
||||
|
|
@ -39314,9 +39346,10 @@
|
|||
}
|
||||
},
|
||||
"react-devtools-core": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.19.1.tgz",
|
||||
"integrity": "sha512-2wJiGffPWK0KggBjVwnTaAk+Z3MSxKInHmdzPTrBh1mAarexsa93Kw+WMX88+XjN+TtYgAiLe9xeTqcO5FfJTw==",
|
||||
"version": "4.24.3",
|
||||
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.24.3.tgz",
|
||||
"integrity": "sha512-+htKZxLxDN14jhRG3+IXRiJqNSGHUiPYrMtv9e7qlZxcbKeJjVs+C/hd8kZF5rydp3faBwFN6ZpTaZnLA3/ZGA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"shell-quote": "^1.6.1",
|
||||
"ws": "^7"
|
||||
|
|
@ -39458,6 +39491,23 @@
|
|||
"react-is": "^17.0.1"
|
||||
}
|
||||
},
|
||||
"react-devtools-core": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-4.19.1.tgz",
|
||||
"integrity": "sha512-2wJiGffPWK0KggBjVwnTaAk+Z3MSxKInHmdzPTrBh1mAarexsa93Kw+WMX88+XjN+TtYgAiLe9xeTqcO5FfJTw==",
|
||||
"requires": {
|
||||
"shell-quote": "^1.6.1",
|
||||
"ws": "^7"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": {
|
||||
"version": "7.5.7",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz",
|
||||
"integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==",
|
||||
"requires": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "17.0.2",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
|
|
@ -43031,6 +43081,7 @@
|
|||
"version": "7.5.5",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
|
||||
"integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
"xcode": {
|
||||
|
|
|
|||
|
|
@ -151,6 +151,7 @@
|
|||
"mock-async-storage": "2.2.0",
|
||||
"nock": "13.2.4",
|
||||
"patch-package": "6.4.7",
|
||||
"react-devtools-core": "4.24.3",
|
||||
"react-native-svg-transformer": "1.0.0",
|
||||
"react-test-renderer": "17.0.2",
|
||||
"tough-cookie": "4.0.0",
|
||||
|
|
|
|||
Loading…
Reference in a new issue