diff --git a/ui/component/claimTags/index.js b/ui/component/claimTags/index.js index a0280f138..385aca981 100644 --- a/ui/component/claimTags/index.js +++ b/ui/component/claimTags/index.js @@ -1,10 +1,10 @@ import { connect } from 'react-redux'; -import { makeSelectTagsForUri } from 'redux/selectors/claims'; +import { selectTagsForUri } from 'redux/selectors/claims'; import { selectFollowedTags } from 'redux/selectors/tags'; import ClaimTags from './view'; const select = (state, props) => ({ - tags: makeSelectTagsForUri(props.uri)(state), + tags: selectTagsForUri(state, props.uri), followedTags: selectFollowedTags(state), }); diff --git a/ui/redux/reducers/tags.js b/ui/redux/reducers/tags.js index 4edd4fbf7..c3be1baf2 100644 --- a/ui/redux/reducers/tags.js +++ b/ui/redux/reducers/tags.js @@ -65,11 +65,22 @@ export default handleActions( [ACTIONS.USER_STATE_POPULATE]: (state: TagState, action: { data: { tags: ?Array } }) => { const { tags } = action.data; if (Array.isArray(tags)) { + const next = tags && tags.filter((tag) => typeof tag === 'string'); + const prev = state.followedTags; + + if (next && prev && prev.length === next.length && prev.every((value, index) => value === next[index])) { + // No changes + return state; + } + + // New state return { ...state, - followedTags: tags, + followedTags: next || [], }; } + + // Purge 'followedTags' return { ...state, }; diff --git a/ui/redux/selectors/claims.js b/ui/redux/selectors/claims.js index 81d3e54dd..2235a5cfc 100644 --- a/ui/redux/selectors/claims.js +++ b/ui/redux/selectors/claims.js @@ -270,6 +270,11 @@ export const makeSelectTotalPagesInChannelSearch = (uri: string) => return byChannel['pageCount']; }); +export const selectMetadataForUri = createCachedSelector(selectClaimForUri, (claim, uri) => { + const metadata = claim && claim.value; + return metadata || (claim === undefined ? undefined : null); +})((state, uri) => uri); + export const makeSelectMetadataForUri = (uri: string) => createSelector(makeSelectClaimForUri(uri), (claim) => { const metadata = claim && claim.value; @@ -537,6 +542,10 @@ export const makeSelectMyChannelPermUrlForName = (name: string) => return matchingClaim ? matchingClaim.permanent_url : null; }); +export const selectTagsForUri = createCachedSelector(selectMetadataForUri, (metadata: ?GenericMetadata) => { + return (metadata && metadata.tags) || []; +})((state, uri) => uri); + export const makeSelectTagsForUri = (uri: string) => createSelector(makeSelectMetadataForUri(uri), (metadata: ?GenericMetadata) => { return (metadata && metadata.tags) || []; diff --git a/ui/redux/selectors/tags.js b/ui/redux/selectors/tags.js index c75fbaa39..1651f14d9 100644 --- a/ui/redux/selectors/tags.js +++ b/ui/redux/selectors/tags.js @@ -1,16 +1,16 @@ // @flow import { createSelector } from 'reselect'; -const selectState = (state: { tags: TagState }) => state.tags || {}; +type State = { tags: TagState }; + +const selectState = (state: State) => state.tags || {}; export const selectKnownTagsByName = createSelector(selectState, (state: TagState): KnownTags => state.knownTags); -export const selectFollowedTagsList = createSelector(selectState, (state: TagState): Array => - state.followedTags.filter(tag => typeof tag === 'string') -); +export const selectFollowedTagsList = (state: State) => selectState(state).followedTags; export const selectFollowedTags = createSelector(selectFollowedTagsList, (followedTags: Array): Array => - followedTags.map(tag => ({ name: tag.toLowerCase() })).sort((a, b) => a.name.localeCompare(b.name)) + followedTags.map((tag) => ({ name: tag.toLowerCase() })).sort((a, b) => a.name.localeCompare(b.name)) ); export const selectUnfollowedTags = createSelector( @@ -19,7 +19,7 @@ export const selectUnfollowedTags = createSelector( (tagsByName: KnownTags, followedTags: Array): Array => { const followedTagsSet = new Set(followedTags); let tagsToReturn = []; - Object.keys(tagsByName).forEach(key => { + Object.keys(tagsByName).forEach((key) => { if (!followedTagsSet.has(key)) { const { name } = tagsByName[key]; tagsToReturn.push({ name: name.toLowerCase() }); @@ -31,6 +31,6 @@ export const selectUnfollowedTags = createSelector( ); export const makeSelectIsFollowingTag = (tag: string) => - createSelector(selectFollowedTags, followedTags => { - return followedTags.some(followedTag => followedTag.name === tag.toLowerCase()); + createSelector(selectFollowedTags, (followedTags) => { + return followedTags.some((followedTag) => followedTag.name === tag.toLowerCase()); });