-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Chat component refactor #849
Conversation
- Extract `usePeerSocials`, `renderItem` and `getItemType` - Add optional `lastMessages` parameter in `getListArray` to limit the number of returned messages in preview - Remove `readOnly` prop from `Chat` component, simplifying logic for padding and focus states - Replace `ConverseChat` with the newly refactored `Chat` component - Remove default export
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Just a small question about duplicated code
@@ -460,6 +478,112 @@ export default function Chat({ readOnly = false }: { readOnly?: boolean }) { | |||
); | |||
} | |||
|
|||
// Lightweight chat preview component used for longpress on chat | |||
export function ChatPreview() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that we cleaned the component and extracted some hooks & methods from it but still there is a lot of copy/paste here. why do we feel a new component is better than a readOnly parameter? do we need to maintain both?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that doing optional props or using composable pattern can have a fine line.
I also don't often like composable when we know that most of the things we extract we know we won't reuse them many time in the app.
But I think for the animation performance issue it's still worth it to do it here.
It's also easier to understand and isolate component in that way instead of having so many different ways a component can render and react.
Optional props are really not recommended for that. Especially in big component.
I also think that 1-2 lines hooks like those for example are perfectly fine and actually perfect way to make our component composable.
const peerSocials = usePeerSocials();
const isSplitScreen = useIsSplitScreen();
We could even add more to make sure that if we change something in our chat we only change it once by adding:
function useAnimatedListView(conversation) {
const conversationNotPendingRef = useRef(
conversation && !conversation.pending
);
const AnimatedListView =
conversationNotPendingRef.current && Platform.OS !== "web"
? ReanimatedFlashList
: ReanimatedFlatList;
return AnimatedListView;
}
And
function useIsShowingPlaceholder(listArray, isBlockedPeer, conversation) {
return listArray.length === 0 || isBlockedPeer || !conversation;
}
Just my opinion. Happy to chat more about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Further I think that needs to be memoized in some way, I'm pretty sure
const AnimatedListView =
conversationNotPendingRef.current && Platform.OS !== "web"
? ReanimatedFlashList
: ReanimatedFlatList;
Is causing a large bit of rerendering since it's a new component each time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @nmalzieu @thierryskoda and @alexrisch – I've just pushed an update with more custom hooks, also memoized the AnimatedListView
components/Chat/Chat.tsx
Outdated
const useIsShowingPlaceholder = ( | ||
listArray: MessageToDisplay[], | ||
isBlockedPeer: boolean, | ||
conversation: XmtpConversationWithUpdate | undefined | ||
): boolean => { | ||
return listArray.length === 0 || isBlockedPeer || !conversation; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like that when there's more than 1 argument we use object arguments instead. But my own opinion. Not sure if we have some specifics docs around that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For a hook like that I would do this. (again just my own opinion lol)
const useIsShowingPlaceholder = (args: {
listArray: MessageToDisplay[];
isBlockedPeer: boolean;
hasConversation: boolean;
}): boolean => {
return args.listArray.length === 0 || args.isBlockedPeer || ! args.hasConversation;
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @thierryskoda
Thanks for your feedback. As you suggested, I've refactored useIsShowingPlaceholder
and useRenderItem
to use the object parameter pattern. I did direct destructuring in the function parameters rather than using 'args'.
Cheers!
1a27f73
to
65a046a
Compare
65a046a
to
b969291
Compare
Refactor Chat component and optimize message handling for chat preview (long press on chat > auxiliary preview)
readOnly
props in the chat component, and create a dedicated, more lightweight<ChatPreview />
component insteadusePeerSocials
,renderItem
andgetItemType
lastMessages
parameter ingetListArray
to limit the number of returned messages in<ChatPreview />
readOnly
prop fromChat
component, simplifying logic for padding and focus statesConverseChat
with the newly refactoredChat
componentscreens/ConversationReadOnly.tsx
(onLeaveScreen)Linked to: #819 (comment)