Maintain react-player light mode after user clicks on thumbnail - react-player

I'm using the light={true} setting in my ReactPlayer component to show a thumbnail on a list of videos. This works fine on the initial load. However, when a user clicks on the thumbnail, I open a modal to play the video (in a separate ReactPlayer component). When the user closes the modal and returns to the list, the video they clicked on is now no longer in "thumbnail mode".
I have tried passing a light: true parameter from my reducer on the MODAL_CLOSED action, and I can successfully see that value coming into my component, but setting the light property to that value has no effect on the thumbnail mode of my ReactPlayer component.
Is there a way to keep the ReactPlayer in thumbnail mode always, regardless of user interaction?

I had a similar issue and this is how I kept it in "light" mode
Add a ref with useRef
// Create a ref
const playerRef = React.useRef(null)
// Your video url
const yourUrl = "https://yourUrlHere..."
return (
<ReactPlayer
ref={playerRef}
light={true}
url={yourUrl}
/>
):
create a useEffect that calls ref.current.showPreview() anytime there is a change that causes ReactPlayer to leave "light" mode
// This will make the player go back to "light" mode
React.useEffect(() => {
if (playerRef) {
playerRef.current.showPreview();
}
}, [index]);
I also made a CodeSandbox if you'd like to check it out

Related

react-headroom - momentarily disable when animating scroll from another component

I have have a tabs-component that becomes sticky when a user scrolls past it's scroll position on the page. When a tab is clicked it will scroll the user up or down, depending on where their current scroll position is, in relation to the related tab-content's scroll position.
Is it possible to momentarily disable/reactivate the react-headroom functionality from another component, when required?
Ideally, when scroll-up is initiated via these tabs, I wish to trigger the react-headroom hide-header functionality, if the header is already shown, or disable the show-header functionality, if the header is already hidden. Any suggestions how one would achieve this?
Thanks in advance.
I ended up resolving this by storing a boolean value of false in useState, to control the toggling of the react-headroom's disable prop. As the scrollIntoView animation is based on time, not distance travelled, so you can rely 😅 on setting a setTimeout of 500ms to reset the the useRef value back to its original state.
When I want to trigger a scroll and/or disable the header hide/show functionality, I place a useRef on the scroll-trigger, which an onClick event calls a function. Within this function, I set useState to true (to activate the disable prop & disable the header), animate the page, then use a setTimeout of 500ms to reset the useRef value back it original state, which will re-activate the header functionality.
import { useRef, useState } from 'react';
import Headroom from 'react-headroom';
const SiteHeader = (): JSX.Element => {
const [headroomDisabled, setHeadroomDisabled] = useState(false);
const myRef = useRef<HTMLDivElement>(null);
const myRef2 = useRef<HTMLDivElement>(null);
const executeScroll = () => myRef.current?.scrollIntoView();
const executeScrollUp = () => {
setHeadroomDisabled(true);
myRef2.current?.scrollIntoView();
setTimeout(() => {
setHeadroomDisabled(true);
}, 500);
};
return (
<>
<Headroom disable={headroomDisabled}>
<h2>Test header content</h2>
</Headroom>
<div ref={myRef2}>Element to scroll to</div>
<button onClick={executeScroll}> Click to scroll </button>
<div style={{ marginTop: '150vh' }}></div>
<div ref={myRef}>Element to scroll to</div>
<button onClick={executeScrollUp}> Click to scroll </button>
</>
);
};
export default SiteHeader;
I ended up taking this a step further and placing this logic in some global state, as so any component could utilise this functionality 🍻

Passed the button text to state, but text reverted back during page refresh in React hooks

I have a record with two buttons, on click on Accept button should send the data back to server and display the text to Save and should not change the text afterwards ( should change only for clicked buttons).
In the below example, it is changing the text during on click, which is fine, but while refreshing the page it set back the text to Accept. Could someone please advise on how can I fix this ?
import { useState, useEffect } from "react";
import "./styles.css";
export default function App() {
const [acceptPlayer, setAcceptPlayer] = useState("Accept");
const postData = (e) => {
const text = "Save";
setAcceptPlayer(text);
};
return (
<div className="App">
<div>
<button onClick={postData} value="accept">
{acceptPlayer}
</button>
</div>
</div>
);
}
https://codesandbox.io/s/admiring-austin-1w1g38?file=/src/App.js
There is nothing wrong with this code. It's the expected behavior of the react. React or any other framework does not persist state on refresh That's the responsibility of the BE.
Solution:
When you can get API to show the data on the page, In the API response, you can return the data in the following format:
{
isAccepted: false,
//...something else
}
When you click on accept button and call the API BE is responsible for updating the isAccepted flag from the next time the API is called. You will get the following response:
{
isAccepted: true,
//...something else
}
Based on isAccepted flag you can toggle the button text.
Of course, it would go back to Accept because react only stores state locally. So every time you refresh the page it will go back to its initial state.
So if you want to get the updated state in your component then you have to fetch the latest data from the database in useEffect and have to set it to a state.

Input fields inside react overlays doesnt work in modal

I have modal screen (using react-bootstrap), on modal screen i have multiple overlays (popup menus) linked to items. These overlays has inputs, and when i click on input it immediately loses focus. I cant figure out whats wrong, because another one popup menu, that i have on normal screen, not modal, works fine. Tried to set autofocus, but it immediately loses too.
I wrote example, https://codesandbox.io/s/rkemy
I think it is somehow connected with popper, because bootstrap overlay uses it, dont know where to dig
The fix provided in the other response is a workaround that doesn't fix the real cause of the issue.
The issue is caused by an internal logic of the Modal component of react-overlay library that is a dependency library of react-bootstrap.
Specifically, the issue is caused by code listed below
const handleEnforceFocus = useEventCallback(() => {
if (!enforceFocus || !isMounted() || !modal.isTopModal()) {
return;
}
const currentActiveElement = activeElement();
if (
modal.dialog &&
currentActiveElement &&
!contains(modal.dialog, currentActiveElement)
) {
modal.dialog.focus();
}
});
that enforce the focus on the first modal open as soon as that modal lose the focus, like when you move the focus on the input.
In order to solve the issue, you have to pass the enforceFocus={false} to your Modal component.
The documentation of the API can be found here: https://react-bootstrap.github.io/react-overlays/api/Modal#enforceFocus
As the docs says:
Generally this should never be set to false as it makes the Modal less accessible to assistive technologies, like screen readers. but in your scenario this is a need to work properly.
Solution is to wrap Overlay in container:
import React from "react";
import { Overlay } from "react-bootstrap";
import { X } from "react-bootstrap-icons";
export const PopupMenuWrapper = (props) => {
const { target, title, show, onClose, children } = props;
const ref = React.useRef(null);
return (
<div ref={ref}>
<Overlay
container = {ref.current}
target={target.current}
show={show}
placement="bottom-start"
rootClose={true}
onHide={onClose}
>
...
</div>
...

Using React, how can I maintain state while playing and pausing a video?

I'm building a video player in React and I'm trying to keep track of whether or not the video is playing. Naturally, I'm thinking of using React state to set a boolean to true or false.
The problem is that whenever I play the video and try to update the state, my video seems to be reloaded to the DOM and the play / pause state is lost.
const refVideo = useRef();
const [isPlaying, setIsPlaying] = useState(false);
function playVideo() {
if(refVideo && refVideo.current) {
if(refVideo.current.paused) {
setIsPlaying(true);
refVideo.current.requestFullscreen();
refVideo.current.play();
} else {
setIsPlaying(false);
refVideo.current.pause();
}
}
return false;
}
return (
<section>
<video src="video.mp4" ref={refVideo}></video>
<Button onClick={(e) => playVideo(e)} text="Play / Pause />
</section>
);
My Button component handles the playVideo() function but setIsPlaying(true) seems to re-render the video, preventing it from playing. Is there a better approach to this?
One recommendation for maintaining state on re-render would be using a state manager such as Redux. Creating a pause or play alongside a player timestamp can ensure that the player maintains both status and position on any React render changes.
Have you thought about using that boolean in a cookie? In that way you dont have to change the state and re render. You look at the cookie on the onClick event and then change the boolean and play or stop the video. Just an idea
I'm using the default html5 player in my react app but I need the UI to depend on whether the video is playing or not. Setting up a simple event listener in my useEffect function worked for me:
videoRef.current.addEventListener('play', () => {
setVideoPlaying(true)
})
videoRef.current.addEventListener('pause', () => {
setVideoPlaying(false)
})

Restore scroll position after toggled a modal in react with useContext

Goal
Restore the scoll position of the window after the a div has toggled from position fixed to none.
Problem
Restoring the scroll position doesnt work although i get it saved correctly to the state.
Description
I have a page where a modal is opened via onClick. Therefore i created a "ToggleModalContext" to pass the props to the modal on the one hand and to the background div on the other hand. I want to modify the background div with setting the css property position to fixed to avoid that the background is scrolled instead of the content of the modal.
When the modal is closed, the position: fixed is removed and i want to restore the scroll position of the window.
This last step doesnt work. Maybe someone else has an idea?
ToggleModalContext (Thats the context, where the scroll restore function is called)
import React from "react";
export const ToggleModalContext = React.createContext();
export const ModalProvider = props => {
const [toggle, setToggle] = React.useState(false);
const [scrollPosition, setScrollPosition] = React.useState();
function handleToggle() {
if (toggle === false) {
setScrollPosition(window.pageYOffset); // When the Modal gets opened, the scrollposition is saved correctly
}
if (toggle === true) {
window.scrollTo(0, scrollPosition); // Restoring doesnt work.
}
setToggle(!toggle);
}
return (
<ToggleModalContext.Provider value={[toggle, handleToggle]}>
{props.children}
</ToggleModalContext.Provider>
);
};
Maybe somebody has a idea?
Maybe i have to use useEffect? But how?
Thanks for your time in advance :)
From the description you have provided, you are using a fixed position on the background div to remove scrolling on the window when you open your modal
On the other hand, you are calling
if (toggle === true) { window.scrollTo(0, scrollPosition);}
before your modal has closed. At this time, the background div is in a fixed position and there is no where to scroll to.
You need to ensure that your modal has safely closed and your background div is back to its normal position before calling this function. To see the behavior, you can use a setTimeout function and call this function there with a set time e.g.
setTimeout(() => window.scrollTo(0, scrollPosition), 2000);

Resources