Add And Remove Before Uploading
The following example shows how to use the autoUpload
prop, which is by default set to true, when set to false.
When it is off, the uploader will aggregate the files (and batches) until it receives an explicit instruction to begin uploading.
In React, this is typically done using the Context API.
The working code example can be found in this sandbox:
Code
In this guide we will create a list of items that each will show progress for its respective item and will also allow the user to cancel(abort) the upload before or during the upload.
The List Item
import React, { useState, memo } from "react";
import styled from "styled-components";
import { Circle } from "rc-progress";
import { RiDeleteBin2Fill } from "react-icons/ri";
import { ImCancelCircle } from "react-icons/im";
import { FcCheckmark } from "react-icons/fc";
import {
useItemFinalizeListener,
useItemProgressListener,
useAbortItem,
FILE_STATES
} from "@rpldy/uploady";
const StyledCircle = styled(Circle)`
width: 36px;
height: 36px;
margin-right: 10px;
`;
const ItemProgress = memo(({ id }) => {
const { completed } = useItemProgressListener(id) || { completed: 0 };
return (
<StyledCircle
percent={completed}
strokeWidth={2}
trailColor="rgb(175,180,176)"
strokeColor={{
"0%": "#ffecb1",
"100%": "#9eea9e"
}}
/>
);
});
const ItemWrapper = styled.div`
display: flex;
align-items: center;
margin: 10px 0;
justify-content: flex-start;
`;
const ItemName = styled.span`
display: inline-block;
margin: 0 10px;
${({ $aborted }) => ($aborted ? "color: gray;" : undefined)}
${({ $success }) => ($success ? "color: green;" : undefined)}
`;
const UploadListItem = ({ item }) => {
const [itemState, setState] = useState(item.state);
const abortItem = useAbortItem();
useItemFinalizeListener((item) => {
setState(item.state);
}, item.id);
const isAborted = itemState === FILE_STATES.ABORTED,
isSuccess = itemState === FILE_STATES.FINISHED,
isFinished = ![FILE_STATES.PENDING, FILE_STATES.UPLOADING].includes(
itemState
);
const onAbortItem = () => {
abortItem(item.id);
};
return (
<ItemWrapper>
{!isFinished && <ItemProgress id={item.id} />}
{isAborted && <ImCancelCircle size={36} color="gray" />}
{isSuccess && <FcCheckmark size={36} />}
<ItemName $aborted={isAborted} $success={isSuccess}>
{item.file.name}
</ItemName>
{!isFinished && <RiDeleteBin2Fill size={32} onClick={onAbortItem} />}
</ItemWrapper>
);
};
We render the Item details (file name) with an abort button using the useAbortItem hook.
We show the progress for each item using the useItemProgressListener hook. The progress component is taken from rc-progress.
Notice we pass the ID of the item to the progress hook, to make sure we get the data for the right item
We also show the status of the item (success, aborted, etc) using the useItemFinalizeListener hook.
Again, we pass the item.id
to make sure we only get the relevant state.
The List
import React, { useState } from "react";
import styled from "styled-components";
import {
useUploady,
useBatchAddListener,
} from "@rpldy/uploady";
const ListContainer = styled.section`
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: center;
margin-top: 20px;
`;
const UploadList = () => {
const { processPending } = useUploady();
const [items, setItems] = useState([]);
useBatchAddListener((batch) => {
setItems((items) => items.concat(batch.items));
});
return (
<ListContainer>
{items.map((item) => (
<UploadListItem key={item.id} item={item} />
))}
{items.length ? <button onClick={processPending}>Upload</button> : null}
</ListContainer>
);
};
The list component uses the useBatchAddListener hook to get updated when new items are added to the queue.
For each of the items added we render the UploadListItem
component we defined in the previous section.
It also uses the processPending context method to initiate the actual upload processing when the user clicks the button.
Uploady
import Uploady from "@rpldy/uploady";
import UploadButton from "@rpldy/upload-button";
export default function App() {
return (
<Uploady
autoUpload={false}
destination={{ url: "[upload-url]" }}
>
<div className="App">
<UploadButton>Add Files</UploadButton>
<UploadList />
</div>
</Uploady>
);
}
Our App component in this example renders the Uploady that we must use to wrap any functionality
that depends on the Uploady functionality (eX: accessing the context). Here we specify autoUpload={false}
to allow users to add files
multiple times before the upload requests are sent.
We use the UploadButton component to show the file selection modal to the user
and then render the UploadList
component we defined in the previous section.