MM-50577 Replaced makeCreateAriaLabelForPost with better memoized usePostAriaLabel (#22833)

Этот коммит содержится в:
Harrison Healey
2023-04-13 16:24:20 -04:00
коммит произвёл GitHub
родитель 024a5472ff
Коммит 21b72c7607
5 изменённых файлов: 62 добавлений и 50 удалений

Просмотреть файл

@@ -1,36 +1,24 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React, {useRef} from 'react'; import React from 'react';
import {useSelector} from 'react-redux';
import {useIntl} from 'react-intl';
import {Post} from '@mattermost/types/posts'; import {Post} from '@mattermost/types/posts';
import {GlobalState} from 'types/store'; import {usePostAriaLabel} from 'utils/post_utils';
import {makeCreateAriaLabelForPost} from 'utils/post_utils';
export type Props = React.HTMLProps<HTMLDivElement> & { export type Props = React.HTMLProps<HTMLDivElement> & {
labelPrefix?: string;
post: Post; post: Post;
} }
const PostAriaLabelDiv = React.forwardRef((props: Props, ref: React.Ref<HTMLDivElement>) => { const PostAriaLabelDiv = React.forwardRef((props: Props, ref: React.Ref<HTMLDivElement>) => {
const { const {
children, children,
labelPrefix,
post, post,
...otherProps ...otherProps
} = props; } = props;
const intl = useIntl(); const ariaLabel = usePostAriaLabel(post);
const createAriaLabelForPost = useRef(makeCreateAriaLabelForPost());
let ariaLabel = useSelector<GlobalState, string>((state) => createAriaLabelForPost.current(state, post)(intl));
if (labelPrefix) {
ariaLabel = labelPrefix + ariaLabel;
}
return ( return (
<div <div

Просмотреть файл

@@ -77,4 +77,18 @@ describe('LatestPostReader', () => {
expect(span.prop('children')).toContain(author.username); expect(span.prop('children')).toContain(author.username);
expect(span.prop('children')).toContain('enero'); expect(span.prop('children')).toContain('enero');
}); });
test('should be able to handle an empty post array', () => {
const {mountOptions} = mockStore(baseState);
const props = {
...baseProps,
postIds: [],
};
const wrapper = mount(<LatestPostReader {...props}/>, mountOptions);
const span = wrapper.childAt(0);
expect(span.prop('children')).toEqual('');
});
}); });

Просмотреть файл

@@ -1,8 +1,7 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React, {useMemo, useRef} from 'react'; import React, {useMemo} from 'react';
import {useIntl} from 'react-intl';
import {useSelector} from 'react-redux'; import {useSelector} from 'react-redux';
import {getPost} from 'mattermost-redux/selectors/entities/posts'; import {getPost} from 'mattermost-redux/selectors/entities/posts';
@@ -11,27 +10,18 @@ import {Post} from '@mattermost/types/posts';
import {GlobalState} from 'types/store'; import {GlobalState} from 'types/store';
import {getLatestPostId, makeCreateAriaLabelForPost} from 'utils/post_utils'; import {getLatestPostId, usePostAriaLabel} from 'utils/post_utils';
interface Props { interface Props {
postIds?: string[]; postIds?: string[];
} }
const LatestPostReader = (props: Props): JSX.Element => { const LatestPostReader = (props: Props): JSX.Element => {
const intl = useIntl();
const {postIds} = props; const {postIds} = props;
const latestPostId = useMemo(() => getLatestPostId(postIds || []), [postIds]); const latestPostId = useMemo(() => getLatestPostId(postIds || []), [postIds]);
const latestPost = useSelector<GlobalState, Post>((state) => getPost(state, latestPostId)); const latestPost = useSelector<GlobalState, Post>((state) => getPost(state, latestPostId));
const createAriaLabelForPost = useRef(makeCreateAriaLabelForPost()); const ariaLabel = usePostAriaLabel(latestPost);
const ariaLabel = useSelector<GlobalState, string>((state) => {
if (!latestPost) {
return '';
}
return createAriaLabelForPost.current(state, latestPost)(intl);
});
return ( return (
<span <span

Просмотреть файл

@@ -71,13 +71,13 @@ export function getReactionsForPosts(state: GlobalState): RelationOneToOne<Post,
export function makeGetReactionsForPost(): (state: GlobalState, postId: Post['id']) => { export function makeGetReactionsForPost(): (state: GlobalState, postId: Post['id']) => {
[x: string]: Reaction; [x: string]: Reaction;
} | undefined | null { } | undefined {
return createSelector('makeGetReactionsForPost', getReactionsForPosts, (state: GlobalState, postId: string) => postId, (reactions, postId) => { return createSelector('makeGetReactionsForPost', getReactionsForPosts, (state: GlobalState, postId: string) => postId, (reactions, postId) => {
if (reactions[postId]) { if (reactions[postId]) {
return reactions[postId]; return reactions[postId];
} }
return null; return undefined;
}); });
} }

Просмотреть файл

@@ -1,7 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import {IntlShape} from 'react-intl'; import {IntlShape, useIntl} from 'react-intl';
import {useMemo} from 'react';
import {useSelector} from 'react-redux';
import {createSelector} from 'reselect'; import {createSelector} from 'reselect';
@@ -17,6 +21,8 @@ import {haveIChannelPermission} from 'mattermost-redux/selectors/entities/roles'
import {getCurrentTeamId, getTeam} from 'mattermost-redux/selectors/entities/teams'; import {getCurrentTeamId, getTeam} from 'mattermost-redux/selectors/entities/teams';
import {makeGetDisplayName, getCurrentUserId, getUser, UserMentionKey, getUsersByUsername} from 'mattermost-redux/selectors/entities/users'; import {makeGetDisplayName, getCurrentUserId, getUser, UserMentionKey, getUsersByUsername} from 'mattermost-redux/selectors/entities/users';
import {memoizeResult} from 'mattermost-redux/utils/helpers';
import {Channel} from '@mattermost/types/channels'; import {Channel} from '@mattermost/types/channels';
import {ClientConfig, ClientLicense} from '@mattermost/types/config'; import {ClientConfig, ClientLicense} from '@mattermost/types/config';
import {ServerError} from '@mattermost/types/errors'; import {ServerError} from '@mattermost/types/errors';
@@ -42,8 +48,8 @@ import {allAtMentions} from 'utils/text_formatting';
import {isMobile} from 'utils/user_agent'; import {isMobile} from 'utils/user_agent';
import * as Utils from 'utils/utils'; import * as Utils from 'utils/utils';
import * as Emoticons from './emoticons';
import EmojiMap from './emoji_map'; import EmojiMap from './emoji_map';
import * as Emoticons from './emoticons';
const CHANNEL_SWITCH_IGNORE_ENTER_THRESHOLD_MS = 500; const CHANNEL_SWITCH_IGNORE_ENTER_THRESHOLD_MS = 500;
@@ -443,27 +449,41 @@ export function makeGetMentionsFromMessage(): (state: GlobalState, post: Post) =
); );
} }
export function makeCreateAriaLabelForPost(): (state: GlobalState, post: Post) => (intl: IntlShape) => string { export function usePostAriaLabel(post: Post | undefined) {
const getReactionsForPost = makeGetUniqueReactionsToPost(); const intl = useIntl();
const getDisplayName = makeGetDisplayName();
const getMentionsFromMessage = makeGetMentionsFromMessage();
return createSelector( const getDisplayName = useMemo(makeGetDisplayName, []);
'makeCreateAriaLabelForPost', const getReactionsForPost = useMemo(makeGetReactionsForPost, []);
(state: GlobalState, post: Post) => post, const getMentionsFromMessage = useMemo(makeGetMentionsFromMessage, []);
(state: GlobalState, post: Post) => getDisplayName(state, post.user_id),
(state: GlobalState, post: Post) => getReactionsForPost(state, post.id), const createAriaLabelMemoized = memoizeResult(createAriaLabelForPost);
(state: GlobalState, post: Post) => get(state, Preferences.CATEGORY_FLAGGED_POST, post.id, null) != null,
getEmojiMap, return useSelector((state: GlobalState) => {
(state: GlobalState, post: Post) => getMentionsFromMessage(state, post), if (!post) {
(state: GlobalState) => getTeammateNameDisplaySetting(state), return '';
(post, author, reactions, isFlagged, emojiMap, mentions, teammateNameDisplaySetting) => { }
return (intl: IntlShape) => createAriaLabelForPost(post, author, isFlagged, reactions ?? {}, intl, emojiMap, mentions, teammateNameDisplaySetting);
}, const authorDisplayName = getDisplayName(state, post.user_id);
const reactions = getReactionsForPost(state, post?.id);
const isFlagged = get(state, Preferences.CATEGORY_FLAGGED_POST, post.id, null) != null;
const emojiMap = getEmojiMap(state);
const mentions = getMentionsFromMessage(state, post);
const teammateNameDisplaySetting = getTeammateNameDisplaySetting(state);
return createAriaLabelMemoized(
post,
authorDisplayName,
isFlagged,
reactions,
intl,
emojiMap,
mentions,
teammateNameDisplaySetting,
); );
});
} }
export function createAriaLabelForPost(post: Post, author: string, isFlagged: boolean, reactions: Record<string, Reaction>, intl: IntlShape, emojiMap: EmojiMap, mentions: Record<string, UserProfile>, teammateNameDisplaySetting: string): string { export function createAriaLabelForPost(post: Post, author: string, isFlagged: boolean, reactions: Record<string, Reaction> | undefined, intl: IntlShape, emojiMap: EmojiMap, mentions: Record<string, UserProfile>, teammateNameDisplaySetting: string): string {
const {formatMessage, formatTime, formatDate} = intl; const {formatMessage, formatTime, formatDate} = intl;
let message = post.state === Posts.POST_DELETED ? formatMessage({ let message = post.state === Posts.POST_DELETED ? formatMessage({