React file input onChange not changing the picture? - javascript

I am getting a thumbnail from the user for a particular store. When the file Browse button is clicked, and an image is opened, this sets the thumbnail for the given store; however, I have also added a small x button on the top right of the thumbnail whose purpose in life is to remove this picture and to add a new one. The main problem that I am facing is when I select a thumbnail, and when I click on the x button, it removes the image, but if I choose the same drawn image, it does not add it as a thumbnail. So I have to select a different image to choose the old one.
import thumbnail from "../../../../Assets/thumbnail.png";
import deleteicon from "../../../../Assets/close.svg";
const thumbimage = dataType64toFile(thumbnail);
const [image, setImage] = useState(thumbimage);
const [filename, setFileName] = useState("Upload Image");
const [picture, setPicture] = useState(thumbnail);
const [close, setClose] = useState(false);
{close && (
<img
src={deleteicon}
alt="Delete Thumbnail"
className="thumbnail-close"
onClick={() => {
setImage(thumbimage);
setPicture(thumbnail);
setFileName("Upload Image");
setClose(false);
}}
/>
)}
<Form.File
type="file"
label={filename}
onChange={(e) => {
setImage(e.target.files[0]);
setFileName(e.target.files[0].name);
setPicture(URL.createObjectURL(e.target.files[0]));
setClose(true);
}}
custom
/>

I had recently created the same gallery of images, but my approach involved a custom hook file outside my component, i.e. I just put all my useStates and handler function outside and imported it from there.
first a tweak, don't use const [close, setClose] = useState(false); instead check using image.
set your file and image as null as and when you click delete icon
regarding thumbnail and other don't set em! instead place the icon in the container and when an image is selected let it cover it!

Related

Delete a Container with an Anchor

I'm new to React and I'm creating a Wiki of my repositories on GitHub.
So, I want to remove that item from my list when I click "Remover" and open the repository on a new page when I click "Ver repositório".
But there's is my problem!
When I click the red anchor, it does remove, like I expected. Also, when I click the blue Anchor, it open the repository page and ALSO removes the list. What should I do?
This is the function that I created to remove the repository:
const handleRemoveRepo = (id) => {
const remove = repos.filter((repo) => repo.id !== repo.id);
setRepos(remove);
if ((repo) => repo.id === repo.id) {
return null;
}
And this is the container to map everything:
<Container>
{repos.map(repo => <ItemRepo handleRemoveRepo={handleRemoveRepo} repo={repo} />)}
</Container>
My container comes from this index.js:
<ItemContainer onClick={handleRemove}>
<h3>{repo.name}</h3>
<p>{repo.full_name}</p>
Ver repositório <br />
Remover
<hr />
</ItemContainer>
Thanks in advance.
React App page for example
I tried switching the conditional on my function, exporting a new function on ItemRepo, but both didn't work.
The "remove" click handler is assigned to the container, so it will be invoked if you click anywhere in the container:
<ItemContainer onClick={handleRemove}>
If it should only be invoked when clicking a specific link, assign the click hander to that specific link instead:
<a href="#" className="remove" onClick={handleRemove}>Remover</a>
As an aside... This shouldn't be a link. It's not navigating the user anywhere, but is just performing an action in code. A <button> is a more semantically appropriate element for that. Which can be styled to not have the defaul button background, or styled however you want.

React Native Material - How to display loading when button is pressed

I am using React Native Material and i would like to use "loading" when a button is clicked. When the button is not clicked, it should only display the button.
Is it also possible when loading is displayed, it will disappear after 5 seconds or when i navigate to a different page?
I have tried to use an if statement when onPress is clicked to display loading but this displays an error.
https://www.react-native-material.com/docs/components/button
Code:
<Button
title="Submit Answers"
onPress={CalculateTotal}
loading
/>
Create a state variable for loading and set it false. So that whenever navigating to the component from another page, that will disable the loading.set loading true on button click and add a timeout for disabling it.
const [loading, setLoading] = useState(false);
const CalculateTotal =()=>{
setLoading(true);
setTimeout(()=>{
setLoading(false);
},5000)
}
<Button
title="Submit Answers"
onPress={CalculateTotal}
loading={loading}
/>
You need to create a loading state and change that state according to button press ex:
const [loading, setLoading] = useState(true);
return (
<Button
onPress={() => setLoading(!loading)}
title="Submit Answers"
onPress={CalculateTotal}
loading={loading}
/>
)

Potential issue related to React hooks asked for job interview

So I have a React job interview and have this piece of code in my assignment to close and modal box:
const App = (): ReactElement => {
const [isOpen, setIsOpen] = useState<boolean>(false);
const renderApp = (): ReactElement => {
if (isOpen) {
return <FeedbackForm onClose={() => setIsOpen(false)} />;
}
return <button onClick={() => setIsOpen(true)}>Open modal</button>;
}
if (isOpen) {
return <>
<div className='App'>
<FeedbackForm onClose={() => setIsOpen(false)} />
</div>
</>
}
return <>
<div className='App'>{renderApp()}</div>
}
export default Feedback;
So here I have an App component that has a Modal component and a simple hook that has a boolean value that indicates if the modal is open or not. The modal starts off as closed, so the initial value is false. The button to open the modal is separate from the button that has to close the modal. The button to close the modal is within the Modal component while the button to open it is in the App component. Because they're both separate buttons, they can explicitly set the value to either true or false.
Now, on this topic, I received this question from the code reviewer:
Could you explain the potential issue of the following code?
const [isOpen, setIsOpen] = useState(false)
const toggle = () => setIsOpen(!isOpen);
I can't exactly see the problem in this snippet. I've tried running it with a button that calls toggle() and I see it updating the state perfectly fine. What is the potential issue the interviewer is talking about here?
In the toggle function, we are setting the state based on the current state value. React performs updates in batches and it is a possibility that when we run toggle() multiple times, the state is not updated for each subsequent run. So, to make sure that we don't lose the state updates from the previous runs, we can do something like the following:
const toggle = () => setIsOpen((prevIsOpen) => !prevIsOpen);
Now, in your scenario, it might not happen because we are showing/hiding modal based on toggle click which changes the views completely, but we can't be sure and can't take chances for production deployment. If it were something else, like showing/hiding of expansion panel, sidebar, etc. then the issue would be easily visible if you clicked toggle button simultaneously, with minimal delay between clicks.

Input click can't be triggered programanticly on iOS <12

I'm having an issue with triggering the opening of a file dialogue on older iOS devices, specifically, the issue seems to be on devices that still run iOS 12.
I'm using the React-Dropzone package to create a dropzone for files, but also adding a way to tab the area to open the file dialogue to select files.
I then use Hammerjs to detect onTab events.
What I can establish, by adding an alert to be fired when onTab is called, is that the onTab event is firing and that it is the functions that are meant to open the dialogue that is not triggering the file dialogue to open on older iOS devices.
const FileUploadDropzone = () => {
...
const {getRootProps, getInputProps, open, inputRef} = useDropzone({
// Disable click and keydown behavior
noClick: true,
noKeyboard: true,
});
const handleTap = useCallback(() => {
// specific function created by React-Dropzone to open the dialog
open();
// also tried to trigger the input click directly using a ref (have confirmted that the input is correctly referenced)
inputRef.current.click();
}, [allowInteract, uploading, open]);
return (
<Hammer onTap={handleTap}>
<div {...getRootProps()}>
<input {...getInputProps()}/>
{children}
</div>
</Hammer>
);
};
From what I have read, the input cannot have styles set to display:none, if it does then you cannot programmatically trigger opening the file dialogue.
So I have set the styles as following:
input {
visibility: hidden;
height: 0px;
width: 0px;
}
What I've also tried to do is to wrap the input and the child element passed to the component in a label, hoping that clicking on a label to open the dialogue will be better supported, but even that is not working.
So now I am at a loss, I don't understand how to get this to work on these older iOS < 12 devices.
The issue seems to be related to an issue with fact that Safari on iOS 12 does not like it when there is any delay between the custom click event and until the input click event is called programmatically. Since the input in my case is deeply nested into the DOM, it causes an issue when the bubbling of the event takes to long.
To get around this issue, I had to create a hack, to append the file input into the DOM to make it as shallow of a grandchild as I could of the <body>.
I followed this article to utilise React.createPortal to append the input outside of the component. https://www.jayfreestone.com/writing/react-portals-with-hooks
I created a function to create an empty div at the bottom of the top <div> off the React application.
function usePortal(cssSelector) {
const rootElemRef = React.useRef(document.createElement('div'));
useEffect(
function setupElement() {
const {current} = rootElemRef;
const parentElem = document.querySelector(cssSelector);
parentElem?.appendChild(current);
return function removeElement() {
current.remove();
};
},
[id]
);
return rootElemRef.current;
}
Then created a component that would append its child a custom div, created by the function above
const Modal = ({children}) => {
const target = usePortal('#react-root-div');
return ReactDOM.createPortal(children, target);
};
And then simply wrap the input element with the Modal component and it will be appended (almost) to the bottom of the DOM tree.
<Modal>
<input {...getInputProps()} />
</Modal>

Wordpress Gutenberg Media Upload Video Gallery

I want to have exactly the Media Upload Popup that is used when supplying the gallery attribute to the <MediaUpload> Component. Difference to normal Mediaupload is, that you see a sidebar on the left, and after selecting the items, you reach a view, where you can reorder media like in first image below, not like in the second one that appears with the code I am using:
<MediaUpload
onSelect={ this.onSelectMedia }
/*todo here should be gallery attr but it will disable video selection*/
allowedTypes={ [ 'image', 'video' ] }
accept="image/*,video/*"
multiple
value={ this.media.map( ( m ) => m.mediaId ) }
render={ ( { open } ) => (
<IconButton
label={ __( 'Edit Media' ) }
icon="images-alt2"
onClick={ open }
/>
) }
/>
When I add the gallery attribute, the allowedTypes will somehow be overridden by the gallery attribute and only images will be shown in the MediaUpload Window.
First Image, how it is
Second Image, what i need (but with image + video showing)
I think this has nothing to do with the MediaUpload component itself but with the underlying logic that wordpress only allows attachments of type image in its built-in gallery. As soon as you add the prop gallery to the component the media modal will default to the gallery edit frame. Maybe it’s possible to extend the gallery type to also allow other mime-types.

Categories