I'm new to React and React hooks and very confused about how to trigger a re-render when a state variable changes and I have a useEffect that monitors that state.
Is it possible to trigger renderFileItems to rerun? It is called using {renderFileItems(files)}
in the returned html. While I do see useEffect being called I'm not sure how to trigger the re-render for that area, I'm also ok with full re-render of the page but not sure how to trigger that either.
export default function FileUpload() {
const [files, setFiles] = useState();
useEffect(() => {
// what do I do here?
console.log("CHANGE"); // I do see this getting printed when I add a file
}, [files, fileStatus]);
const remove = (filename) => {
if (files == undefined) {
return;
}
var i = 0;
while (i < files.length) {
if (files[i] === filename) {
files.splice(i, 1);
} else {
++i;
}
}
setFiles(files);
};
const renderFileItems = (filelist) =>
filelist == undefined ? (
<></>
) : (
filelist.map((f) => (
<li className="flex" key={f}>
{f}
<button onClick={remove(f)}>
<TrashIcon
aria-hidden="true"
className="inline-block align-middle size-5 shrink-0"
/>
</button>
</li>
))
);
const fileHandler = (filesArg) => {
// does some logic with filesArg then updates Files state var.
setFiles(/*transformed filesArg*/);
};
return (
<AppLayout>
<div className="flex flex-col">
<div className="flex items-center justify-center w-full items-center justify-center w-full pr-24 pl-24 pt-12">
<label
id="drop-zone"
className="flex flex-col items-center justify-center w-full h-32 border-2 border-dashed rounded-lg cursor-pointer bg-gray-50 hover:bg-gray-100 border-gray-300"
onDragOver={dragOverImageChange}
onDragLeave={dragLeaveChange}
onDrop={dropHandle}
>
<div className="flex flex-col items-center justify-center pt-5 pb-6 gap-y-2">
<p className="mb-2 text-md text-black font-semibold">
Click to upload or drag and drop
</p>
<input
id="dropzone-file-input"
type="file"
className="hidden"
onChange={fileSelectedHandler}
accept=".csv"
multiple="True"
/>
</div>
</label>
</div>
<div className="flex py-12 w-full mx-auto pl-24">
<ul
className="flex flex-col gap-y-1 justify-stretch items-stretch font-semibold text-gray-600"
id="files-show"
>
{renderFileItems(files)}
</ul>
</div>
</div>
</AppLayout>
);
}
If I have to split out the renderFileItems as its own component, I am confused how to have it call the remove() function which will have to modify the files state var tracked in the parent component.
Thanks for any help!
In React we don't change state directly. It have own way to deal with state changes, see here.
To trigger the change, you have to pass a new data on the setState
method, this it also will trigger a rerender.
Extra
remove(f)
will execute the remove
method immediately.
If your intention is pass the f
as a parameter, you have to pass a anon function in the onClick
prop executing your method.
Example:
<button onClick={() => remove(f)}>