Skip to content
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

Merged
merged 4 commits into from
Oct 4, 2024
Merged

Chat component refactor #849

merged 4 commits into from
Oct 4, 2024

Conversation

lourou
Copy link
Member

@lourou lourou commented Sep 30, 2024

Refactor Chat component and optimize message handling for chat preview (long press on chat > auxiliary preview)

  • Remove the readOnly props in the chat component, and create a dedicated, more lightweight <ChatPreview /> component instead
  • Extract usePeerSocials, renderItem and getItemType
  • Add optional lastMessages parameter in getListArray to limit the number of returned messages in <ChatPreview />
  • Remove readOnly prop from Chat component, simplifying logic for padding and focus states
  • Replace ConverseChat with the newly refactored Chat component
  • Remove default export
  • Remove unused code in screens/ConversationReadOnly.tsx (onLeaveScreen)

Linked to: #819 (comment)

- 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
@lourou lourou requested a review from a team as a code owner September 30, 2024 13:18
Copy link
Contributor

@nmalzieu nmalzieu left a 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

components/Chat/Chat.tsx Outdated Show resolved Hide resolved
@@ -460,6 +478,112 @@ export default function Chat({ readOnly = false }: { readOnly?: boolean }) {
);
}

// Lightweight chat preview component used for longpress on chat
export function ChatPreview() {
Copy link
Contributor

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?

Copy link
Collaborator

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.

Copy link
Collaborator

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

Copy link
Member Author

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

@lourou lourou requested a review from nmalzieu October 2, 2024 15:39
Comment on lines 258 to 274
const useIsShowingPlaceholder = (
listArray: MessageToDisplay[],
isBlockedPeer: boolean,
conversation: XmtpConversationWithUpdate | undefined
): boolean => {
return listArray.length === 0 || isBlockedPeer || !conversation;
};
Copy link
Collaborator

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.

Copy link
Collaborator

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;
};

Copy link
Member Author

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!

@lourou lourou force-pushed the lr/chat-preview-refacto branch from 1a27f73 to 65a046a Compare October 4, 2024 08:40
@lourou lourou force-pushed the lr/chat-preview-refacto branch from 65a046a to b969291 Compare October 4, 2024 08:47
@lourou lourou merged commit 655bcd0 into main Oct 4, 2024
3 checks passed
@lourou lourou deleted the lr/chat-preview-refacto branch October 4, 2024 09:35
technoplato pushed a commit that referenced this pull request Dec 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants