Skip to content

Commit a9cb4e0

Browse files
Merge branch 'master' of github.com:GetStream/stream-chat-react into rc
2 parents 5aec7bf + 46c9add commit a9cb4e0

File tree

2 files changed

+28
-32
lines changed

2 files changed

+28
-32
lines changed

src/components/MessageInput/MessageInput.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import type { MessageToSend } from '../../context/ChannelActionContext';
2121
import type { CustomTrigger, SendMessageOptions, UnknownType } from '../../types/types';
2222
import type { URLEnrichmentConfig } from './hooks/useLinkPreviews';
2323
import type { CustomAudioRecordingConfig } from '../MediaRecorder';
24-
import { useHandleDragAndDropQueuedFiles } from './WithDragAndDropUpload';
24+
import { useRegisterDropHandlers } from './WithDragAndDropUpload';
2525

2626
export type EmojiSearchIndexResult = {
2727
id: string;
@@ -141,7 +141,7 @@ const MessageInputProvider = <V extends CustomTrigger = CustomTrigger>(
141141
emojiSearchIndex: props.emojiSearchIndex ?? emojiSearchIndex,
142142
});
143143

144-
useHandleDragAndDropQueuedFiles(messageInputContextValue);
144+
useRegisterDropHandlers();
145145

146146
return (
147147
<MessageInputContextProvider<V> value={messageInputContextValue}>

src/components/MessageInput/WithDragAndDropUpload.tsx

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
1+
import React, { useCallback, useContext, useEffect, useMemo, useRef } from 'react';
22
import { useDropzone } from 'react-dropzone';
33
import clsx from 'clsx';
44
import type { CSSProperties, ElementType, PropsWithChildren } from 'react';
@@ -11,34 +11,27 @@ import {
1111
import type { MessageInputContextValue } from '../../context';
1212

1313
const DragAndDropUploadContext = React.createContext<{
14-
fileQueue: File[];
15-
addFilesToQueue: ((files: File[]) => void) | null;
16-
removeFilesFromQueue: ((files: File[]) => void) | null;
14+
subscribeToDrop: ((fn: (files: File[]) => void) => () => void) | null;
1715
}>({
18-
addFilesToQueue: null,
19-
fileQueue: [],
20-
removeFilesFromQueue: null,
16+
subscribeToDrop: null,
2117
});
2218

2319
export const useDragAndDropUploadContext = () => useContext(DragAndDropUploadContext);
2420

2521
/**
26-
* @private To maintain top -> bottom data flow, the drag-and-drop functionality allows dragging any files to the queue - the closest
27-
* `MessageInputProvider` will be notified through `DragAndDropUploadContext.fileQueue` and starts the upload with `uploadNewAttachments`,
28-
* forwarded files are removed from the queue immediately after.
22+
* @private This hook should be used only once directly in the `MessageInputProvider` to
23+
* register `uploadNewFiles` functions of the rendered `MessageInputs`. Each `MessageInput`
24+
* will then be notified when the drop event occurs from within the `WithDragAndDropUpload`
25+
* component.
2926
*/
30-
export const useHandleDragAndDropQueuedFiles = ({
31-
uploadNewFiles,
32-
}: MessageInputContextValue) => {
33-
const { fileQueue, removeFilesFromQueue } = useDragAndDropUploadContext();
27+
export const useRegisterDropHandlers = ({ uploadNewFiles }: MessageInputContextValue) => {
28+
const { subscribeToDrop } = useDragAndDropUploadContext();
3429

3530
useEffect(() => {
36-
if (!removeFilesFromQueue) return;
31+
const unsubscribe = subscribeToDrop?.(uploadNewFiles);
3732

38-
uploadNewFiles(fileQueue);
39-
40-
removeFilesFromQueue(fileQueue);
41-
}, [fileQueue, removeFilesFromQueue, uploadNewFiles]);
33+
return unsubscribe;
34+
}, [subscribeToDrop, uploadNewFiles]);
4235
};
4336

4437
/**
@@ -71,7 +64,7 @@ export const WithDragAndDropUpload = ({
7164
className?: string;
7265
style?: CSSProperties;
7366
}>) => {
74-
const [files, setFiles] = useState<File[]>([]);
67+
const dropHandlersRef = useRef<Set<(f: File[]) => void>>(new Set());
7568
const { acceptedFiles = [], multipleUploads } = useChannelStateContext();
7669
const { t } = useTranslationContext();
7770

@@ -91,13 +84,16 @@ export const WithDragAndDropUpload = ({
9184
[acceptedFiles],
9285
);
9386

94-
const addFilesToQueue = useCallback((files: File[]) => {
95-
setFiles((cv) => cv.concat(files));
87+
const subscribeToDrop = useCallback((fn: (files: File[]) => void) => {
88+
dropHandlersRef.current.add(fn);
89+
90+
return () => {
91+
dropHandlersRef.current.delete(fn);
92+
};
9693
}, []);
9794

98-
const removeFilesFromQueue = useCallback((files: File[]) => {
99-
if (!files.length) return;
100-
setFiles((cv) => cv.filter((f) => files.indexOf(f) === -1));
95+
const handleDrop = useCallback((files: File[]) => {
96+
dropHandlersRef.current.forEach((fn) => fn(files));
10197
}, []);
10298

10399
const { getRootProps, isDragActive, isDragReject } = useDropzone({
@@ -109,20 +105,20 @@ export const WithDragAndDropUpload = ({
109105
: false,
110106
multiple: multipleUploads,
111107
noClick: true,
112-
onDrop: isWithinMessageInputContext
113-
? messageInputContext.uploadNewFiles
114-
: addFilesToQueue,
108+
onDrop: isWithinMessageInputContext ? messageInputContext.uploadNewFiles : handleDrop,
115109
});
116110

117111
// nested WithDragAndDropUpload components render wrappers without functionality
118112
// (MessageInputFlat has a default WithDragAndDropUpload)
119-
if (dragAndDropUploadContext.removeFilesFromQueue !== null) {
113+
if (dragAndDropUploadContext.subscribeToDrop !== null) {
120114
return <Component className={className}>{children}</Component>;
121115
}
122116

123117
return (
124118
<DragAndDropUploadContext.Provider
125-
value={{ addFilesToQueue, fileQueue: files, removeFilesFromQueue }}
119+
value={{
120+
subscribeToDrop,
121+
}}
126122
>
127123
<Component {...getRootProps({ className, style })}>
128124
{/* TODO: could be a replaceable component */}

0 commit comments

Comments
 (0)