Re-rendering improvements for like/unlike (#2180)
* Add a few memos * Memo PostDropdownBtn better * More memo * More granularity * Extract PostContent * Fix a usage I missed * oopszio/stable
parent
a5e25a7a16
commit
5c701f8e0b
|
@ -328,7 +328,9 @@ let PostThreadItemLoaded = ({
|
||||||
</View>
|
</View>
|
||||||
<PostDropdownBtn
|
<PostDropdownBtn
|
||||||
testID="postDropdownBtn"
|
testID="postDropdownBtn"
|
||||||
post={post}
|
postAuthor={post.author}
|
||||||
|
postCid={post.cid}
|
||||||
|
postUri={post.uri}
|
||||||
record={record}
|
record={record}
|
||||||
style={{
|
style={{
|
||||||
paddingVertical: 6,
|
paddingVertical: 6,
|
||||||
|
|
|
@ -102,10 +102,6 @@ let FeedItemInner = ({
|
||||||
}): React.ReactNode => {
|
}): React.ReactNode => {
|
||||||
const {openComposer} = useComposerControls()
|
const {openComposer} = useComposerControls()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const [limitLines, setLimitLines] = useState(
|
|
||||||
() => countLines(richText.text) >= MAX_POST_LINES,
|
|
||||||
)
|
|
||||||
|
|
||||||
const href = useMemo(() => {
|
const href = useMemo(() => {
|
||||||
const urip = new AtUri(post.uri)
|
const urip = new AtUri(post.uri)
|
||||||
return makeProfileLink(post.author, 'post', urip.rkey)
|
return makeProfileLink(post.author, 'post', urip.rkey)
|
||||||
|
@ -134,10 +130,6 @@ let FeedItemInner = ({
|
||||||
})
|
})
|
||||||
}, [post, record, openComposer])
|
}, [post, record, openComposer])
|
||||||
|
|
||||||
const onPressShowMore = React.useCallback(() => {
|
|
||||||
setLimitLines(false)
|
|
||||||
}, [setLimitLines])
|
|
||||||
|
|
||||||
const outerStyles = [
|
const outerStyles = [
|
||||||
styles.outer,
|
styles.outer,
|
||||||
pal.view,
|
pal.view,
|
||||||
|
@ -286,6 +278,41 @@ let FeedItemInner = ({
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
<PostContent
|
||||||
|
moderation={moderation}
|
||||||
|
richText={richText}
|
||||||
|
postEmbed={post.embed}
|
||||||
|
postAuthor={post.author}
|
||||||
|
/>
|
||||||
|
<PostCtrls post={post} record={record} onPressReply={onPressReply} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
FeedItemInner = memo(FeedItemInner)
|
||||||
|
|
||||||
|
let PostContent = ({
|
||||||
|
moderation,
|
||||||
|
richText,
|
||||||
|
postEmbed,
|
||||||
|
postAuthor,
|
||||||
|
}: {
|
||||||
|
moderation: PostModeration
|
||||||
|
richText: RichTextAPI
|
||||||
|
postEmbed: AppBskyFeedDefs.PostView['embed']
|
||||||
|
postAuthor: AppBskyFeedDefs.PostView['author']
|
||||||
|
}): React.ReactNode => {
|
||||||
|
const pal = usePalette('default')
|
||||||
|
const [limitLines, setLimitLines] = useState(
|
||||||
|
() => countLines(richText.text) >= MAX_POST_LINES,
|
||||||
|
)
|
||||||
|
|
||||||
|
const onPressShowMore = React.useCallback(() => {
|
||||||
|
setLimitLines(false)
|
||||||
|
}, [setLimitLines])
|
||||||
|
|
||||||
|
return (
|
||||||
<ContentHider
|
<ContentHider
|
||||||
testID="contentHider-post"
|
testID="contentHider-post"
|
||||||
moderation={moderation.content}
|
moderation={moderation.content}
|
||||||
|
@ -312,29 +339,25 @@ let FeedItemInner = ({
|
||||||
href="#"
|
href="#"
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
{post.embed ? (
|
{postEmbed ? (
|
||||||
<ContentHider
|
<ContentHider
|
||||||
testID="contentHider-embed"
|
testID="contentHider-embed"
|
||||||
moderation={moderation.embed}
|
moderation={moderation.embed}
|
||||||
moderationDecisions={moderation.decisions}
|
moderationDecisions={moderation.decisions}
|
||||||
ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)}
|
ignoreMute={isEmbedByEmbedder(postEmbed, postAuthor.did)}
|
||||||
ignoreQuoteDecisions
|
ignoreQuoteDecisions
|
||||||
style={styles.embed}>
|
style={styles.embed}>
|
||||||
<PostEmbeds
|
<PostEmbeds
|
||||||
embed={post.embed}
|
embed={postEmbed}
|
||||||
moderation={moderation.embed}
|
moderation={moderation.embed}
|
||||||
moderationDecisions={moderation.decisions}
|
moderationDecisions={moderation.decisions}
|
||||||
/>
|
/>
|
||||||
</ContentHider>
|
</ContentHider>
|
||||||
) : null}
|
) : null}
|
||||||
</ContentHider>
|
</ContentHider>
|
||||||
<PostCtrls post={post} record={record} onPressReply={onPressReply} />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</Link>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
FeedItemInner = memo(FeedItemInner)
|
PostContent = memo(PostContent)
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
outer: {
|
outer: {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React from 'react'
|
import React, {memo} from 'react'
|
||||||
import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
|
import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
|
||||||
import {Text} from './text/Text'
|
import {Text} from './text/Text'
|
||||||
import {TextLinkOnWebOnly} from './Link'
|
import {TextLinkOnWebOnly} from './Link'
|
||||||
|
@ -29,7 +29,7 @@ interface PostMetaOpts {
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PostMeta(opts: PostMetaOpts) {
|
let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const displayName = opts.author.displayName || opts.author.handle
|
const displayName = opts.author.displayName || opts.author.handle
|
||||||
const handle = opts.author.handle
|
const handle = opts.author.handle
|
||||||
|
@ -92,6 +92,8 @@ export function PostMeta(opts: PostMetaOpts) {
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
PostMeta = memo(PostMeta)
|
||||||
|
export {PostMeta}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useMemo} from 'react'
|
import React, {memo, useMemo} from 'react'
|
||||||
import {Image, StyleSheet, View} from 'react-native'
|
import {Image, StyleSheet, View} from 'react-native'
|
||||||
import Svg, {Circle, Rect, Path} from 'react-native-svg'
|
import Svg, {Circle, Rect, Path} from 'react-native-svg'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
|
@ -43,13 +43,13 @@ interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
|
||||||
|
|
||||||
const BLUR_AMOUNT = isWeb ? 5 : 100
|
const BLUR_AMOUNT = isWeb ? 5 : 100
|
||||||
|
|
||||||
export function DefaultAvatar({
|
let DefaultAvatar = ({
|
||||||
type,
|
type,
|
||||||
size,
|
size,
|
||||||
}: {
|
}: {
|
||||||
type: UserAvatarType
|
type: UserAvatarType
|
||||||
size: number
|
size: number
|
||||||
}) {
|
}): React.ReactNode => {
|
||||||
if (type === 'algo') {
|
if (type === 'algo') {
|
||||||
// Font Awesome Pro 6.4.0 by @fontawesome -https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc.
|
// Font Awesome Pro 6.4.0 by @fontawesome -https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2023 Fonticons, Inc.
|
||||||
return (
|
return (
|
||||||
|
@ -112,14 +112,16 @@ export function DefaultAvatar({
|
||||||
</Svg>
|
</Svg>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
DefaultAvatar = memo(DefaultAvatar)
|
||||||
|
export {DefaultAvatar}
|
||||||
|
|
||||||
export function UserAvatar({
|
let UserAvatar = ({
|
||||||
type = 'user',
|
type = 'user',
|
||||||
size,
|
size,
|
||||||
avatar,
|
avatar,
|
||||||
moderation,
|
moderation,
|
||||||
usePlainRNImage = false,
|
usePlainRNImage = false,
|
||||||
}: UserAvatarProps) {
|
}: UserAvatarProps): React.ReactNode => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
|
||||||
const aviStyle = useMemo(() => {
|
const aviStyle = useMemo(() => {
|
||||||
|
@ -182,13 +184,15 @@ export function UserAvatar({
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
UserAvatar = memo(UserAvatar)
|
||||||
|
export {UserAvatar}
|
||||||
|
|
||||||
export function EditableUserAvatar({
|
let EditableUserAvatar = ({
|
||||||
type = 'user',
|
type = 'user',
|
||||||
size,
|
size,
|
||||||
avatar,
|
avatar,
|
||||||
onSelectNewAvatar,
|
onSelectNewAvatar,
|
||||||
}: EditableUserAvatarProps) {
|
}: EditableUserAvatarProps): React.ReactNode => {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
const {requestCameraAccessIfNeeded} = useCameraPermission()
|
||||||
|
@ -323,14 +327,20 @@ export function EditableUserAvatar({
|
||||||
</NativeDropdown>
|
</NativeDropdown>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
EditableUserAvatar = memo(EditableUserAvatar)
|
||||||
|
export {EditableUserAvatar}
|
||||||
|
|
||||||
export function PreviewableUserAvatar(props: PreviewableUserAvatarProps) {
|
let PreviewableUserAvatar = (
|
||||||
|
props: PreviewableUserAvatarProps,
|
||||||
|
): React.ReactNode => {
|
||||||
return (
|
return (
|
||||||
<UserPreviewLink did={props.did} handle={props.handle}>
|
<UserPreviewLink did={props.did} handle={props.handle}>
|
||||||
<UserAvatar {...props} />
|
<UserAvatar {...props} />
|
||||||
</UserPreviewLink>
|
</UserPreviewLink>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
PreviewableUserAvatar = memo(PreviewableUserAvatar)
|
||||||
|
export {PreviewableUserAvatar}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
editButtonContainer: {
|
editButtonContainer: {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React from 'react'
|
import React, {memo} from 'react'
|
||||||
import {Linking, StyleProp, View, ViewStyle} from 'react-native'
|
import {Linking, StyleProp, View, ViewStyle} from 'react-native'
|
||||||
import Clipboard from '@react-native-clipboard/clipboard'
|
import Clipboard from '@react-native-clipboard/clipboard'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {AppBskyFeedDefs, AppBskyFeedPost, AtUri} from '@atproto/api'
|
import {AppBskyActorDefs, AppBskyFeedPost, AtUri} from '@atproto/api'
|
||||||
import {toShareUrl} from 'lib/strings/url-helpers'
|
import {toShareUrl} from 'lib/strings/url-helpers'
|
||||||
import {useTheme} from 'lib/ThemeContext'
|
import {useTheme} from 'lib/ThemeContext'
|
||||||
import {shareUrl} from 'lib/sharing'
|
import {shareUrl} from 'lib/sharing'
|
||||||
|
@ -19,23 +19,26 @@ import {usePostDeleteMutation} from '#/state/queries/post'
|
||||||
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
||||||
import {useLanguagePrefs} from '#/state/preferences'
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {Shadow} from '#/state/cache/types'
|
|
||||||
import {msg} from '@lingui/macro'
|
import {msg} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {isWeb} from '#/platform/detection'
|
import {isWeb} from '#/platform/detection'
|
||||||
|
|
||||||
export function PostDropdownBtn({
|
let PostDropdownBtn = ({
|
||||||
testID,
|
testID,
|
||||||
post,
|
postAuthor,
|
||||||
|
postCid,
|
||||||
|
postUri,
|
||||||
record,
|
record,
|
||||||
style,
|
style,
|
||||||
}: {
|
}: {
|
||||||
testID: string
|
testID: string
|
||||||
post: Shadow<AppBskyFeedDefs.PostView>
|
postAuthor: AppBskyActorDefs.ProfileViewBasic
|
||||||
|
postCid: string
|
||||||
|
postUri: string
|
||||||
record: AppBskyFeedPost.Record
|
record: AppBskyFeedPost.Record
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
}) {
|
}): React.ReactNode => {
|
||||||
const {hasSession, currentAccount} = useSession()
|
const {hasSession, currentAccount} = useSession()
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
@ -46,13 +49,13 @@ export function PostDropdownBtn({
|
||||||
const toggleThreadMute = useToggleThreadMute()
|
const toggleThreadMute = useToggleThreadMute()
|
||||||
const postDeleteMutation = usePostDeleteMutation()
|
const postDeleteMutation = usePostDeleteMutation()
|
||||||
|
|
||||||
const rootUri = record.reply?.root?.uri || post.uri
|
const rootUri = record.reply?.root?.uri || postUri
|
||||||
const isThreadMuted = mutedThreads.includes(rootUri)
|
const isThreadMuted = mutedThreads.includes(rootUri)
|
||||||
const isAuthor = post.author.did === currentAccount?.did
|
const isAuthor = postAuthor.did === currentAccount?.did
|
||||||
const href = React.useMemo(() => {
|
const href = React.useMemo(() => {
|
||||||
const urip = new AtUri(post.uri)
|
const urip = new AtUri(postUri)
|
||||||
return makeProfileLink(post.author, 'post', urip.rkey)
|
return makeProfileLink(postAuthor, 'post', urip.rkey)
|
||||||
}, [post.uri, post.author])
|
}, [postUri, postAuthor])
|
||||||
|
|
||||||
const translatorUrl = getTranslatorLink(
|
const translatorUrl = getTranslatorLink(
|
||||||
record.text,
|
record.text,
|
||||||
|
@ -60,7 +63,7 @@ export function PostDropdownBtn({
|
||||||
)
|
)
|
||||||
|
|
||||||
const onDeletePost = React.useCallback(() => {
|
const onDeletePost = React.useCallback(() => {
|
||||||
postDeleteMutation.mutateAsync({uri: post.uri}).then(
|
postDeleteMutation.mutateAsync({uri: postUri}).then(
|
||||||
() => {
|
() => {
|
||||||
Toast.show('Post deleted')
|
Toast.show('Post deleted')
|
||||||
},
|
},
|
||||||
|
@ -69,7 +72,7 @@ export function PostDropdownBtn({
|
||||||
Toast.show('Failed to delete post, please try again')
|
Toast.show('Failed to delete post, please try again')
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}, [post, postDeleteMutation])
|
}, [postUri, postDeleteMutation])
|
||||||
|
|
||||||
const onToggleThreadMute = React.useCallback(() => {
|
const onToggleThreadMute = React.useCallback(() => {
|
||||||
try {
|
try {
|
||||||
|
@ -163,8 +166,8 @@ export function PostDropdownBtn({
|
||||||
onPress() {
|
onPress() {
|
||||||
openModal({
|
openModal({
|
||||||
name: 'report',
|
name: 'report',
|
||||||
uri: post.uri,
|
uri: postUri,
|
||||||
cid: post.cid,
|
cid: postCid,
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
testID: 'postDropdownReportBtn',
|
testID: 'postDropdownReportBtn',
|
||||||
|
@ -211,3 +214,6 @@ export function PostDropdownBtn({
|
||||||
</EventStopper>
|
</EventStopper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PostDropdownBtn = memo(PostDropdownBtn)
|
||||||
|
export {PostDropdownBtn}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useCallback} from 'react'
|
import React, {memo, useCallback} from 'react'
|
||||||
import {
|
import {
|
||||||
StyleProp,
|
StyleProp,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
|
@ -27,7 +27,7 @@ import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {Shadow} from '#/state/cache/types'
|
import {Shadow} from '#/state/cache/types'
|
||||||
import {useRequireAuth} from '#/state/session'
|
import {useRequireAuth} from '#/state/session'
|
||||||
|
|
||||||
export function PostCtrls({
|
let PostCtrls = ({
|
||||||
big,
|
big,
|
||||||
post,
|
post,
|
||||||
record,
|
record,
|
||||||
|
@ -39,7 +39,7 @@ export function PostCtrls({
|
||||||
record: AppBskyFeedPost.Record
|
record: AppBskyFeedPost.Record
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
onPressReply: () => void
|
onPressReply: () => void
|
||||||
}) {
|
}): React.ReactNode => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const {openComposer} = useComposerControls()
|
const {openComposer} = useComposerControls()
|
||||||
const {closeModal} = useModalControls()
|
const {closeModal} = useModalControls()
|
||||||
|
@ -71,7 +71,14 @@ export function PostCtrls({
|
||||||
likeCount: post.likeCount || 0,
|
likeCount: post.likeCount || 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [post, postLikeMutation, postUnlikeMutation])
|
}, [
|
||||||
|
post.viewer?.like,
|
||||||
|
post.uri,
|
||||||
|
post.cid,
|
||||||
|
post.likeCount,
|
||||||
|
postLikeMutation,
|
||||||
|
postUnlikeMutation,
|
||||||
|
])
|
||||||
|
|
||||||
const onRepost = useCallback(() => {
|
const onRepost = useCallback(() => {
|
||||||
closeModal()
|
closeModal()
|
||||||
|
@ -89,7 +96,15 @@ export function PostCtrls({
|
||||||
repostCount: post.repostCount || 0,
|
repostCount: post.repostCount || 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [post, closeModal, postRepostMutation, postUnrepostMutation])
|
}, [
|
||||||
|
post.uri,
|
||||||
|
post.cid,
|
||||||
|
post.viewer?.repost,
|
||||||
|
post.repostCount,
|
||||||
|
closeModal,
|
||||||
|
postRepostMutation,
|
||||||
|
postUnrepostMutation,
|
||||||
|
])
|
||||||
|
|
||||||
const onQuote = useCallback(() => {
|
const onQuote = useCallback(() => {
|
||||||
closeModal()
|
closeModal()
|
||||||
|
@ -103,7 +118,16 @@ export function PostCtrls({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
Haptics.default()
|
Haptics.default()
|
||||||
}, [post, record, openComposer, closeModal])
|
}, [
|
||||||
|
post.uri,
|
||||||
|
post.cid,
|
||||||
|
post.author,
|
||||||
|
post.indexedAt,
|
||||||
|
record.text,
|
||||||
|
openComposer,
|
||||||
|
closeModal,
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View style={[styles.ctrls, style]}>
|
<View style={[styles.ctrls, style]}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
|
@ -179,7 +203,9 @@ export function PostCtrls({
|
||||||
{big ? undefined : (
|
{big ? undefined : (
|
||||||
<PostDropdownBtn
|
<PostDropdownBtn
|
||||||
testID="postDropdownBtn"
|
testID="postDropdownBtn"
|
||||||
post={post}
|
postAuthor={post.author}
|
||||||
|
postCid={post.cid}
|
||||||
|
postUri={post.uri}
|
||||||
record={record}
|
record={record}
|
||||||
style={styles.ctrlPad}
|
style={styles.ctrlPad}
|
||||||
/>
|
/>
|
||||||
|
@ -189,6 +215,8 @@ export function PostCtrls({
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
PostCtrls = memo(PostCtrls)
|
||||||
|
export {PostCtrls}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
ctrls: {
|
ctrls: {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, {useCallback} from 'react'
|
import React, {memo, useCallback} from 'react'
|
||||||
import {StyleProp, StyleSheet, TouchableOpacity, ViewStyle} from 'react-native'
|
import {StyleProp, StyleSheet, TouchableOpacity, ViewStyle} from 'react-native'
|
||||||
import {RepostIcon} from 'lib/icons'
|
import {RepostIcon} from 'lib/icons'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
|
@ -17,13 +17,13 @@ interface Props {
|
||||||
onQuote: () => void
|
onQuote: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RepostButton = ({
|
let RepostButton = ({
|
||||||
isReposted,
|
isReposted,
|
||||||
repostCount,
|
repostCount,
|
||||||
big,
|
big,
|
||||||
onRepost,
|
onRepost,
|
||||||
onQuote,
|
onQuote,
|
||||||
}: Props) => {
|
}: Props): React.ReactNode => {
|
||||||
const theme = useTheme()
|
const theme = useTheme()
|
||||||
const {openModal} = useModalControls()
|
const {openModal} = useModalControls()
|
||||||
const requireAuth = useRequireAuth()
|
const requireAuth = useRequireAuth()
|
||||||
|
@ -80,6 +80,8 @@ export const RepostButton = ({
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
RepostButton = memo(RepostButton)
|
||||||
|
export {RepostButton}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
control: {
|
control: {
|
||||||
|
|
Loading…
Reference in New Issue