How to set value of prop in a useEffect? - reactjs

so I'm trying to pass a dynamically generated URL to Image's source prop and, due to React Native limitations, I cannot simply pass a variable as the value of that prop because it won't update to load the image after the variable is set.
So I'm trying to follow the advice here to trigger a change to the source prop.
How can I set the value of a prop in useEffect?
Edit: this is what I'm trying, but still not successfully seeing the image
const [photoUrl, setPhotoUrl] = useState();
useEffect(() => {
async function getSetImg() {
let img = await getImage(job.afterPhoto.uri);
setPhotoUrl(img);
}
if (job) {
getSetImg;
}
}, [job]);
<Image
source={{ uri: photoUrl }}
style={styles.headerImage}
/>

The problem may not be from setting the values with useState/setState.
I have 2 suggestions you can try.
1. Check if Image style is set explicitly
Q) Does the image show when you hardcode the URL directly (without using setState)?
You can try using the Google logo image for uri: https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png
NO (Image don't show): Try the below (style)
YES (Hardcoded image is shown ok): Try #2 (ATS)
From RN Docs on Image:
Note that for network and data images, you will need to manually specify the dimensions of your image!
If your styles.headerImage does not have height and width explicitly defined, the <Image/> component may not show. You can easily check if your <Image/> component is visible by setting the backgroundColor='red' while developing.
2. Check App Transport Security (ATS) settings
Q) Are you using iOS? Is the uri source in https or http?
If you are fetching image in http, check the ATS settings.
Also from RN Docs on ATS:
App Transport Security is a security feature introduced in iOS 9 that rejects all HTTP requests that are not sent over HTTPS.
Suggested fix from another SO question is to add NSAllowsArbitraryLoads in the info.plist.

Related

How to tell if Gatsby Image component has loaded?

I have a GatsbyImage / StaticImage component and I use the onLoad event to trigger an animation. But once the browser has cached the image, the onLoad event never fires again. So if you visit a different page and then return, the animation isn't triggered.
The usual workaround with an ordinary image would be to attach a ref and then check ref.current.complete to see if the image had loaded. But GatsbyImage refuses to take a ref.
So
Is there any way to add a ref to the GatsbyImage component?
Is there any other way to detect if the image has loaded?
Is the only alternative to use an ordinary img tag (and lose out on all the gatsby image magic)?
Is there any way to add a ref to the GatsbyImage component?
Apparently, you can't. According to this GitHub thread it throws the following exception:
Function components cannot be given refs. Attempts to access this ref
will fail. Did you mean to use React.forwardRef()?
That said, you can try using forwardRef() which will give you a valid scope for your use-case.
Is there any other way to detect if the image has loaded?
Not directly. However, you can try the onStartLoad callback which expose the wasCached boolean that gives your more information and control about the browser cache. You can play around with that boolean to trigger the animation again or to use the value globally along with a useState for example:
<GatsbyImage
fadeIn={false}
className="customImg"
onLoad={() => {
// do loading stuff
}}
onStartLoad={({ wasCached }) => {
// do stuff on start of loading
// optionally with the wasCached boolean parameter
}}
onError={(error) => {
// do error stuff
}}
/>
Is the only alternative to use an ordinary img tag (and lose out on all the gatsby image magic)?
You can find a bunch of dependencies to lazy-load, fade, blur, get background primary color, etc of an image but its implementation, behavior, and compatibility will rely on the library itself. So, yes, there are alternatives but I'm not sure if they are worth it.

How to set default image for img tag incase src is invalid in react

How can I set a default image for an img tag in case src link is invalid in react?
I've tried using onerror like so, but it doesn't seem to work.
Im using Next.js and hooks.
<img alt="Site Logo" src="/secondary.jpg" onerror="this.onerror=null; this.src='https://static.thenounproject.com/png/140281-200.png';" />
By invalid, I mean when the src receives a URL and it can't find an image I would like to make it display a default image.
When it can't find an image it will display this
Instead of this, I would like to make it display a default image if it can't find the image from the URL provided.
Usually, this can be done with onerror like above but it doesn't work in react for some reason, whats the alternative solution?
I was facing this issue and couldn't find a working solution anywhere, but I was able to understand an easy one. You can simply do this.
First, you can use useState like this and give your intended image.
const [imgSrc, setImgSrc] = useState("Invalid Image Source");
then, in your image component, you can simply do this. (make sure to spell onError correctly)
<img src={imgSrc} onError = {() => setImgSrc("https://picsum.photos/200")} />
in the setImgSrc() give the image you want as the default.
Hope this was helpful!

How to resolve react-video-js-player failing to load media

Hello I am trying to use the react video js player but I am getting the error below:
The media could not be loaded, either because the server or network failed or because the format is not supported.
At first, I thought maybe it was the video type because Initially it was a .mkvi video I then changed to mp4 and still nothing I get the same error can I please get help
Code Below: VideoList.js
import React from 'react';
import VideoPlayer from 'react-video-js-player';
const VideoList = (props) =>{
let videos = props.listVideos
return(
<div>
{videos.map(video =>{
return(
<div key={video.id}>
<h3>{video.lecturer}</h3>
<VideoPlayer src={video.video} width="720" height="420" playbackRates={[0.5, 1, 3.85, 16]}/>
</div>
)
})}
</div>
)
}
export default VideoList
Like I said on my comments, typically this error will occur if the video is not existing, has issues with the encoding, file extension, etc. See this example I've written.
In the end, I was correct and the video.video object was returning a relative path instead of an absolute path which resulted in an incorrect link.
Regarding the OP's current solution for this issue, this is not an ideal architecture because it will probably fail when you deploy to production, switch domains, or even just switch ports. Concantenating your base url is fine (e.g., http://127.0.0.1:8000/) but I would have this variable as a single source of truth probably residing at a state at the topmost component or as an environment variable so that anytime you change domains, ports, or IP you can simply change this variable and you won't have to go through all of your components 1 by 1.
Example implementation on Class based components:
Parent component:
state = {
base_url: `http://127.0.0.1:8000/api/`, // local dev api
// base_url: `https://production-server:80/api/` // live site api
// or an environment variable as described on my answer
}
Child component:
<VideoPlayer src={`${this.props.base_url}${content.video}`}
So I managed to find the problem behind this, so I was getting data from the API but when I tried to access the video the API was not giving the full URL that is:
http://127.0.0.1:8000/media/lectures/<here_the_name_of_the_lecture_video>
But the API was giving me a relative path media/lectures/<here_the_name_of_the_lecture_video>
So I had to give the remaining the URL that which the API does not give when I render in the video i.e I had to write the following
<VideoPlayer src={`http://127.0.0.1:8000/api${content.video}`}
So I am wondering
Currently, this solution works but is this solution technically good? Because I am to believe that the API should be giving everything that I need I just have to make requests.
Can you please assist me to come up with a more technically viable solution for this problem

React-Stripe-Elements handleCardPayment with saved card

I am switching to payment intents and am trying to reuse a saved card. (react-stripe-elements)
This works quite well right now and instead of
stripe.handleCardPayment(intentData.client_secret);
(as suggested in the docs) I am using the following, because this worked.
stripe.confirmPaymentIntent(intentData.client_secret)
With the first one I always got an error, that the card number is not filled out - seems like it always takes the react-elements-form that is on the same page as a basis.
It worked and I could pay with my saved cards until now, but now I tested it, with the "requires auth on all transactions" card: 4000002760003184
When I use confirmPaymentIntent it just gets stuck on the status: [status] => requires_source_action
How would I go about and show the "confirmation" dialog, as it did with the handleCardPayment method, in case it is needed?
The transactions are all happening on the page and are triggered via react-stripe-elements.
Seems like react-stripe-elements will always take the Elements form context, whenever you have a form initialized (which I had on the same page) and you use the stripe prop.
This is pretty neat, when you fill out the form to add a new credit card, but really annoying, when you don't want to use form data, but your saved card.
I asked the stripe support and they told me, that there is no way to get around this, so I looked around a little more and found, that react-stripe-elements is just using the normal Stripe JS SDk and thereby the window.Stripe object should be available (out of the content) to do this easily.
So this is how I solved it for us:
const { stripe } = this.props;
// if we use a saved payment method and the Stripe obj is available
if (isSavedPaymentMethod && typeof Stripe !== 'undefined') {
// don't use the context bound stripe from react-stripe-elements, but the uninitialized Stripe and pass your key
const stripeOutofBound = Stripe(STRIPE_API_KEY);
await stripeOutofBound.handleCardPayment(
intentData.client_secret,
);
} else {
// otherwise use the react-stripe-elements prop directly, that passes the new credit card form data
await stripe.handleCardPayment(
intentData.client_secret,
);
}

Passing Aws url function directly in image uri makes the image change everytime when any state variable is updated

In my react native app, I am using 'aws-sdk' which works fine but as soon as any state is changed, the image gets reloaded. I think react calls the function whenever the change is detected in my url. And as the aws sdk generates unique url the image reloaded each time a state is changed. I dont want to add an extra variable for image. Like to know how can I fix this i.e pass function in image uri & make the image immutable each time a state is changed. THANKS
My Image UI for e.g is-
<Image
style={{width:100,height:150, resizeMode:'cover'}}
source={{ uri:this.getAwsImageUrl(this.state.imurl) }}
>
</Image>
And My getAwsImageUrl() is-
getAwsImageUrl(imgUrl) {
var s3 = new AWS.S3({accessKeyId:'test',
secretAccessKey:'test', region:'test'});
var img='';
var params = {Bucket: 'test', Key:imgUrl};
img=s3.getSignedUrl('getObject', params);
console.log('imgggggggg=',img);
return img;
}

Resources