I have a react app with some complex view logic. There is one view where I need to have different parents and conditional renders. This causes my stream ref to be lost, or a video to restart. Is there anyway to set this up so my video instance can reach the new view state without restarting?
I've tried display none but it messes with my view, visibility hidden restarts the video.
here's a sandbox of my problem.
https://codesandbox.io/s/romantic-wood-qnn2x0?file=/src/App.js:0-1004
Here's one solution I thought of.
import { useState } from "react";
import React from "react";
import "./styles.css";
let flex = {
display: "flex"
};
let leftParent = {};
let VidInstance = React.forwardRef((props, ref) => {
return (
<div style={{ display: !props.mute ? "flex" : "none", width: 200 }}>
<video
controls=""
preload="none"
autoPlay
src="https://archive.org/download/BigBuckBunny_124/Content/big_buck_bunny_720p_surround.mp4"
width="200"
muted={props.mute}
></video>
</div>
);
});
export default function App() {
let [view, setView] = useState(false);
return (
<div className="App">
<flex style={flex}>
<leftParent style={leftParent}>
<Box />
<Box />
<VidInstance key="vid" mute={view} />
</leftParent>
<VidInstance key="vid" mute={!view} />
</flex>
<button onClick={() => setView(!view)}>view</button>
</div>
);
}
let Box = () => {
let boxStyle = {
width: "200px",
margin: "2px",
height: "100px",
background: "blue"
};
return <div style={boxStyle}></div>;
};
Loading both VidInstance at same time to sync their play time.
Wrap VidInstance with a wrapper div and give that div same width as the video to reserve the empty space when your video goes hidden.
Pass mute prop to VidInstance to mute and hide inactive video.
You have to use the tag <source> inside the video tag... its worked for me:
<video width="320" height="240" controls>
<source src="movie.mp4" type="video/mp4">
<source src="movie.ogg" type="video/ogg">
Your browser does not support the video tag.
</video>
Related
Have an issue with react-image-crop. If I change the crop, it works perfectly, but if I just load and then hit save, I get an empty image back. At first I thought maybe its just not loading it, but I can see the croped image on load. And I don't get an "undefined" image back, I get an image with no data in it.
This is how I read the image:
useEffect(() => {
console.log("Got completed crop")
const canvas: HTMLCanvasElement = document.getElementById('canvas') as HTMLCanvasElement
if (canvas) {
console.log("Got canvas")
console.log(canvas.toDataURL())
setCroppedImgUrl(canvas.toDataURL())
} else {
}
}, [completedCrop])
This code gets called every time completedCrop is updated, and I can see that it works when the image is first loaded, BUT, the image it returns on load (independent on what image I am cropping) is
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAAXNSR0IArs4c6QAABGJJREFUeF7t1AEJAAAMAsHZv/RyPNwSyDncOQIECEQEFskpJgECBM5geQICBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAAYPlBwgQyAgYrExVghIgYLD8AAECGQGDlalKUAIEDJYfIEAgI2CwMlUJSoCAwfIDBAhkBAxWpipBCRAwWH6AAIGMgMHKVCUoAQIGyw8QIJARMFiZqgQlQMBg+QECBDICBitTlaAECBgsP0CAQEbAYGWqEpQAgQdWMQCX4yW9owAAAABJRU5ErkJggg==
To initiate the crop, I use the following code:
<div className='d-flex align-items-center gap-4'>
<div className='text-center'>
<p>Crop:</p>
{Boolean(posterSrc) && (
<ReactCrop
crop={crop}
onChange={(_, percentCrop) => {
setCrop(percentCrop)
}}
onComplete={(crop) => setCompletedCrop(crop)}
aspect={aspect}>
<img
style={{maxHeight: previewHeight, maxWidth: previewWidth, objectFit: "cover"}}
ref={imgRef}
alt="Crop me"
src={posterSrc}
onLoad={onImageLoad}/>
</ReactCrop>
)}
</div>
<div className='text-center'>
<p>Preview:</p>
{Boolean(completedCrop) && (
<canvas
id='canvas'
ref={previewCanvasRef}
style={{
objectFit: 'contain',
width: previewWidth,
height: previewHeight,
}}
/>
)}
</div>
</div>
Anyone have any idea what I'm doing so wrong
I'm making a hybrid app with React and Capacitor and I need to render an iOS component (AVPlayerView) mixed in with my HTML. I was wondering if there's any way to create a capacitor plugin (e.g. PlayerPlugin) to handle this. Like:
return (
<div>
<img src="whatever" />
<PlayerPlugin height="300px" width="300px" />
<img src="whatever2" />
</div>
)
Or:
const player = PlayerPlugin({ height: '300px', width: '300px' })
return (
<div>
<img src="whatever" />
{player}
<img src="whatever2" />
</div>
)
And the player would automagically know to place itself between the images.
Alternatively, instead of having it mixed in with HTML, at least making it look like it is, by also passing the position, in addition to the dimensions.
For example:
const player = PlayerPlugin()
const playerRef = useRef(null)
useEffect(() => {
if (!playerRef.current) return
player.height = playerRef.current.offsetHeight
player.width = playerRef.current.offsetWidth
player.top = playerRef.current.offsetLeft
player.left = playerRef.current.offsetTop
player.visible = true
}, [playerRef.current])
return (
<div>
<img src="whatever" />
<div ref="playerRef" style={{ height: '300px', width: '300px' }} />
<img src="whatever2" />
</div>
)
Is it possible to do something like this?
I can't find any examples of accordions where the active class is related to an element outside of the accordion. I'm trying to get an image to change on the side of the accordion, where each image is related to a specific object. I managed to get something working using absolute positioning, but I'm looking for a more elegant solution so I can manipulate styling better.
I can get it to work while the image is inside the accordion under the info text, but can't figure out the styling issue. I think I need to do some refactoring or do away with the array mapping to get it to work but I'm not sure.
Here is a codesandbox of more or less what I want to achieve but without the restriction of absolute positioning - https://codesandbox.io/s/ecstatic-taussig-f084t?file=/src/App.js
You can remove your img tag from your renderedItems and do something like this:
import React, { useState } from "react";
const Accordion = ({ items }) => {
const [activeIndex, setActiveIndex] = useState(0);
const onTitleClick = (index) => {
setActiveIndex(index);
};
const renderedItems = items.map((item, index) => {
const active = index === activeIndex ? "active" : "";
return (
<div key={item.title}>
<div className={`title ${active}`} onClick={() => onTitleClick(index)}>
<i className="dropdown icon"></i>
{item.title}
</div>
<div className={`content ${active}`}>
<p>{item.content}</p>
</div>
</div>
);
});
return (
<div className="container-gallery">
<div className="ui styled accordion">{renderedItems}</div>
<img
className={`content `}
src={`${items[activeIndex].image}`}
style={{
height: "200px",
width: "200px"
}}
alt="img"
/>
</div>
);
};
export default Accordion;
And for the style I don't know what you are using so I made css for the example:
.container-gallery{
display:flex;
flex-wrap:no-wrap;
justify-content: space-between;
}
here a sandBox link
In my react app, this is an array of filenames I get from server side
const photos = ["01-1913.JPG", "01-1913.1.jpg", "01-1913.2.jpg"]
and here is how I use it with JSX
{
photos.map(entry => {
return (
<div key={entry}>
<PhotoItem key={entry} url={`${process.env.REACT_APP_NODE_SERVER}/${entry}`} />
</div>
)
})
}
const PhotoItem = (url) => {
return (
<img
src={url}
onError={this.addDefaultSrc}
alt="photoItem"
style={{
width: "500px",
height: "600px",
border: "1px solid #123C69",
}}
></img>
);
};
```
I can not figure out why I am not getting the photo (only the dummy photo from the onError event I've used) and if it has anything to do with the Object%object error. Any help would be appreciated.
As mentioned in the comments, the PhotoItem component should look like this:
// Note that here props are named "props" instead of "url"
const PhotoItem = (props) => {
return (
<img
src={props.url}
onError={this.addDefaultSrc}
alt="photoItem"
style={{
width: "500px",
height: "600px",
border: "1px solid #123C69",
}}
></img>
);
};
Note that the first argument that a react component receives is props. So even if you name it url, the value that you are looking for url lives in url.url.
I also recommend to deconstruct your props like this:
const PhotoItem = ({url}) => {
return (
<img
src={url}
...
></img>
);
};
I faced this error on the developer console on a Next.js project right after upgrading Next from v10 to v12.
Turns out using an image as <img src={require()}/> is not working anymore, and throws this error.
Instead to fix the issue, you need to use Next's (almost) drop in replacement of Image component as;
import Image from 'next/image'
...
<Image src={require()}/>
This will fix the issue, if your Next project is throwing this error.
Currently using google-maps-react component in a contact form for a sales page. This code has successfully imported the map and it is viewable in the dimensions 450x350. My issue is, is that despite the image being 450x350 the frame or i guess div that the map api sits in still thinks the map is still default size so it pushes my entire site out with white space that is removed when i remove the Map API. No amount of adding styles as dimensions to anything around the map has fixed this.
What do i pass into the map in order to effect the size of the frame and not just the image itself?
import React, { Fragment } from "react";
import ContactForm from "../contactus/ContactForm";
import { Map, Marker, GoogleApiWrapper } from "google-maps-react";
const ContactUs = props => {
const style = {
maxWidth: "450px",
height: "350px",
overflowX: "hidden",
overflowY: "hidden"
};
return (
<Fragment>
<h2 className='lead text-primary text-center'>Get in touch</h2>
<div className='grid-2'>
<div>
<h4>Priority Consulting</h4>
<ul>
<li>
1234 Sherman Way <br />
Sherman Oaks, CA 90210
</li>
<li>info#priorityconsulting.com</li>
<li>1-800-324-3423</li>
</ul>
<Map google={props.google} style={style} />
</div>
<div>
{" "}
<ContactForm />
</div>
</div>
</Fragment>
);
};
export default GoogleApiWrapper({
apiKey: "MYKEY"
})(ContactUs);
I went back into my code and found an updated version, that made it to a final version of the site. Unfortunately the site is no longer live so cant verify if this is the best answer but, like I said its in my code, so it probably solves.
const style = {
maxWidth: "450px",
height: "350px",
overflowX: "hidden",
overflowY: "hidden"
};
const containerStyle = {
maxWidth: "450px",
height: "350px"
};
<Map google={props.google} style={style} containerStyle={containerStyle} />