React component renders before I can set src of image - javascript

I have this application that flashes a series of cards. Some have questions with text. No problem there obviously. But the image source is being retrieved from firebase. On each render I check if it has a question with text, or with an image and if it has an image I query the database for the downloadURL and insert that as the source. If I insert it hard coded it works fine, if I console log the response it's accurate. My problem is I believe that the component renders before I can insert the source dynamically. Code is below. And yes, I know with that many conditionals it looks like a christmas tree and is probably really bad practice.
To save some reading I'll splice it where I make the request here...
useEffect(() => {
if ("imageHolder" in active) {
const asyncFunc = async () => {
setLoading(true);
setImage(true);
await storageRef
.child(active.imageHolder)
.getDownloadURL()
.then(function (url) {
imageSrc = url;
console.log("url returns ", url);
})
.catch(function (error) {
console.log(error);
});
};
asyncFunc();
setLoading(false);
}
}, [active, getQuestions, correctAnswer]);
And where I insert it here
) : image ? (
loading ? (
<h1>Loading</h1>
) : (
<img alt="" src={imageSrc} className="d-inline-block align-top" />
)
) : (
<h3>{active.question}</h3>
)}
</div>
<div className="answerGrid">
{loading ? (
Thanks for any advice at all. And stay healthy!

It might be helpful to see the rest of the code, but given the provided snippets, I'm assuming the problem is with how the imageSrc variable is getting set.
Have you tried managing the imageSrc as state? E.g.
const [imageSrc, setImageSrc] = useState('')
// then use setImageSrc after getting the url
await storageRef
.child(active.imageHolder)
.getDownloadURL()
.then(function (url) {
setImageSrc(url)
console.log("url returns ", url);
})

I think simple decision to this will be adding a logical "or" operator in src
like this
<img alt="" src={imageSrc || ''} className="d-inline-block align-top" />

Related

ReactJS: Data not binding from continuous response

While integrating the aws ivs streaming channel with quiz related metadata, at that time getting the console.log of the metadata records and while passing those records into another component it is not handling any how.
A playground that i have created into codesandobx
PlayerComponent
function PlayerComponent(options) {
useEffect(() => {
const script = document.createElement("script");
script.src = "https://player.live-video.net/1.0.0/amazon-ivs-player.min.js";
script.async = true;
document.body.appendChild(script);
script.onload = (IVSPlayer) => {
if (IVSPlayer.isPlayerSupported) {
const player = IVSPlayer.create();
player.attachHTMLVideoElement(document.getElementById("video-player"));
player.load(
"https://fcc3ddae59ed.us-west-2.playback.live-video.net/api/video/v1/us-west-2.893648527354.channel.xhP3ExfcX8ON.m3u8"
);
player.play();
player.addEventListener(
IVSPlayer.PlayerEventType.TEXT_METADATA_CUE,
(cue) => {
const metadataText = cue.text;
setMetaData(metadataText);
console.log("PlayerEvent - METADATA: ", metadataText);
}
);
}
};
return () => {
document.body.removeChild(script);
};
}, []);
return (
<div ref={divEl}>
<video id="video-player" ref={videoEl} autoPlay controls></video>
{metaData !== undefined ? <QuizComponent metadata={metaData} /> : ""}
</div>
);
}
On QuizComponent would like to render those metadata
export default function QuizComponent(props) {
const questionData = props;
return (
<React.Fragment>
<h2>{questionData.metadata.question}</h2>
</React.Fragment>
);
}
But any how not able to render the data into component.
Ref example of what I am going to implement.
https://codepen.io/amazon-ivs/pen/XWmjEKN?editors=0011
I found the problem. Basically you are referring IVSPlayer as if it was the argument of the arrow function you passed to script onload, while the argument instead is an event (the onload event).
Solution: const {IVSPlayer} = window;. Infact docs say
Once amazon-ivs-player.min.js is loaded, it adds an IVSPlayer variable to the global context.
Docs also explain how to setup with NPM which you may be interested in.
I updated my playground here.
I also suggest you to edit the version of the player as the last one is 1.2.0.

<Image source={require(" ")} /> not displaying correctly?

Im confused that my Image is not being displayed.
This works but its a bit too static. I need a dynamic profile-picture update when uploading a file.
import picture from "../../images/public/600bc441b2b2b62c542bd135profilepicture.jpg";
return(
<div>
<Image className={"profilepicture"} source={picture} alt={"pic"} />
</div>
)
So I implemented it with my Backend-Axios-Call like this:
const [mapimages, setMapImages] = useState(null);
useEffect(() => {
axios.get(API_BASE_URL + '/user/images', payload)
.then(function (response) {
if (response.status >= 200 && response.status < 300) {
const files = response.data.files[0];
const requireimg = require("../../images/public/" + files);
setMapImages(<Image source={requireimg} alt={"TEXT"} />);
} else {
alert("error getting images");
}
})
.catch(function (error) {
console.log("DOWNLOAD: " + error);
});
}, []);
return(
<div>
{mapimages}
</div>
)
Sadly I dont get the Images displayed. It shows the correct path to the File though.
This is the path in my image inspector:
<img alt="TEXT" class="profilepicture" source="/static/media/600bc441b2b2b62c542bd135profilepicture.8a22cb97.jpg">
and navigating
from
http://localhost:3000/#/profile
to
http://localhost:3000/static/media/600bc441b2b2b62c542bd135profilepicture.8a22cb97.jpg
also displays the Image.
I always get this:
I'm clueless because this previously worked. I just forgot to push it to git :(
You should try to replace "source" with "src" inside your image tag

Link component interpolation error nextjs

I am getting this error in Next.js:
Error: The provided 'href' (/subject/[subject]) value is missing query values (subject) to be interpolated properly. Read more: https://err.sh/vercel/next.js/href-interpolation-failed`.
I have a dynamic page set up as /subject/[subject].tsx. Now in my navigation I have:
<Link href={'/subject/${subject}'} passHref><a>{subject}</a></Link>
It works fine when I access the page with different paths but when I am pressing on a button on the page it throws the error above which I imagine is because the component rerenders. If you go to the page in the error it says: Note: this error will only show when the next/link component is clicked not when only rendered.
I have tried to look for a solution and I tried doing:
<Link href={{pathname: '/subject/[subject]', query: {subject: subject}}}></Link>
but nothing changed. I read the docs and it seems that the as prop is only an optional decorator that is not used anymore so I fail to see how that can help me.
I got the same issue when trying to redirect user to locale. I did it in useEffect. After investigate I discovered that on first render router.query is empty, so it's missing required field id. I fix it by using router.isReady
export const useUserLanguageRoute = () => {
const router = useRouter()
useEffect(() => {
const {
locales = [],
locale,
asPath,
defaultLocale,
pathname,
query,
isReady // here it is
} = router
const browserLanguage = window.navigator.language.slice(0, 2)
const shouldChangeLocale =
isReady && // and here I use it
locale !== browserLanguage
&& locale === defaultLocale
&& locales.includes(browserLanguage)
if (shouldChangeLocale) {
router.push(
{
pathname,
query,
},
asPath,
{ locale: browserLanguage }
)
}
}, [router])
}
Another possible solution could be redirect using the router.push function:
const myRedirectFunction = function () {
if (typeof window !== 'undefined') {
router.push({
pathname: router.pathname,
query: {...router.query, myqueryparam: 'myvalue'},
})
}
}
return (
<>
<button onClick={() => {myRedirectFunction()}}> Continue </button>
</>
)
It is important to include ...router.query because there is where the [dynamic] current value is included, so we need to keep it.
Reference: https://github.com/vercel/next.js/blob/master/errors/href-interpolation-failed.md
You better do a null || undefined check in prior.
#Bentasy, Like you rightly pointed out, any re-render of the page is expecting you to pass in the dynamic route params again. The way I avoided page re-rendering with subsequent clicks on the page was to replace Link tag on the page with a label tag. I was using the Next Link tag to navigate between the tabs on this image which generated this same error. So I replaced the Link tags with label tags and the error was solved.
I was having the same problem, this is how I solved it.
While pushing something to the router, we need to give the old values ​​in it.
In that:
const router = useRouter()
router.push({
...router,
pathname: '/your-pathname'
})
try add this function, it work for me:
export async function getServerSideProps(context) {
return {
props: {},
};
}

How do I get my api call to call a different file?

I am using the api http://aws.random.cat/meow and it gives me a result of
{"file": "https://purr.objects-us-east-1.dream.io/i/rEJ7q.jpg"}
The file changes every time I refresh the api call on the browser which gives me a different cat pic. For example, if I refresh it would give me a different .jpg like
{"file": "https://purr.objects-us-east-1.dream.io/i/ferbus.jpg"}
I call the api in my React app, and I want to randomize the cat pic after an onClick of a button. Unfortunately, I get the same picture back when I do my api call. I put the file in an img src, but it doesn't change when I do another api call.
componentDidMount() {
this.getCats();
}
getCats = () => {
axios.get(`http://aws.random.cat/meow`)
.then(res => {
let cats = res.data.file;
console.log(cats)
this.setState({
cats
})
})
.catch(err => console.log(err))
}
render() {
return (
<div>
<img
src={this.state.cats}
alt='cat'
/>
<button onClick={this.getCats}>
Click me
</button>
</div>
);
}
I expect to get a different file every time, but instead I get the same .jpg when I do an onClick.

Force fetched image data to https

I am looking for a solution to force images from a fetch API to be in https rather than http
The API returns image results as http from the fetched JSON file but this is giving warning in the console to Mixed Content
I am fetching in componentDidMount as
componentDidMount() {
var self = this;
const proxyurl = 'https://cors-anywhere.herokuapp.com/';
const url = `//api.tripadvisor.com/api/partner/2.0/location/${this.props
.tripAdvisorId}?key=${AuthKey}`;
fetch(proxyurl + url)
.then(data => data.json())
.then(data => {
self.setState({
reviewData: data,
isLoading: false
});
});
}
and then mapping the data by way
{this.state.reviewData.reviews.map(i => {
return (
<div key={i.id}>
<img src={i.rating_image_url} alt={i.title} />
</div>
);
})}
How can I force the url from {i.rating_image_url} to use https when this is not returned from the fetch?
By using a regular expression, something like:
{this.state.reviewData.reviews.map(i => {
return (
<div key={i.id}>
<img src={i.rating_image_url.replace(/^http:\/\//i, 'https://')} alt={i.title} />
</div>
);
})}
const url = new URL(originalUrl);
url.protocol = url.protocol.replace('http', 'https');
console.log(url.href);
This method uses the built-in URL class to fully parse, and then uses a string replacement on the protocol.
Just change this code to check if you are receiving the image or not
<img src={i.rating_image_url ? i.rating_image_url : i.rating_image_url.replace(/^http:\/\//i, 'https://')} alt={i.title} />
This way we are checking if we are getting its value or not.
For more better understanding you can also do this
{this.state.reviewData.reviews.map(i => {
console.log(i.rating_image_url);
return (
<div key={i.id}>
<img src={i.rating_image_url} alt={i.title} />
</div>
);
})}
This will show whatever data you are receiving in rating_image_url on your browser console.
Hope it helps you.

Categories

Resources