Skip to content

NXT-21175: Migrate VideoPlayer/Video.js to functional component. - #460

Open
alexandrumorariu wants to merge 6 commits into
feature/functionalComponentsfrom
feature/NXT-21175
Open

alexandrumorariu wants to merge 6 commits into
feature/functionalComponentsfrom
feature/NXT-21175

Conversation

@alexandrumorariu

Copy link
Copy Markdown
Contributor

Checklist

  • I have read and understand the contribution guide
  • A CHANGELOG entry is included
  • At least one test case is included for this feature or bug fix
  • I have run automated testing and it is passed
  • Documentation was added or is not needed
  • This is an API breaking change

Issue Resolved / Feature Added

Migrated Video from VideoPlayer to a functional component.

Resolution

Additional Considerations

Links

NXT-21175

Comments

@alexandrumorariu
alexandrumorariu changed the base branch from feature/functionalComponents to develop October 27, 2026 10:53
@alexandrumorariu
alexandrumorariu changed the base branch from develop to feature/functionalComponents October 27, 2026 10:53
@codecov

codecov Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.50746% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 83.85%. Comparing base (ccf5ec6) to head (465d123).
⚠️ Report is 2 commits behind head on feature/functionalComponents.

Files with missing lines Patch % Lines
VideoPlayer/Video.js 98.50% 1 Missing ⚠️
Additional details and impacted files
@@                       Coverage Diff                        @@
##           feature/functionalComponents     #460      +/-   ##
================================================================
+ Coverage                         83.54%   83.85%   +0.30%     
================================================================
  Files                               158      158              
  Lines                              7908     7954      +46     
  Branches                           2446     2454       +8     
================================================================
+ Hits                               6607     6670      +63     
+ Misses                             1011      995      -16     
+ Partials                            290      289       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment thread VideoPlayer/Video.js Outdated
}, []);

// Equivalent of componentWillUnmount
useLayoutEffect(() => () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drop this effect. setVideoRef already calls setMedia(null) when React detaches the ref, on unmount and when setMedia changes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment thread VideoPlayer/Video.js Outdated
Comment on lines +66 to +67
// Keys from the previous render. They replace the instance fields the class mutated in
// `getKeys()`. State is only updated during render when the sources change.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment explains the code by comparing it with the old class
Could we describe what the state is for instead?

Comment thread VideoPlayer/Video.js Outdated
Comment on lines +94 to +96
// React calls the ref callback with `null` when the video is removed or unmounted, and when
// `setMedia` changes, so the previous `setMedia` is always cleared, as `componentDidUpdate` and
// `componentWillUnmount` did.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: “as componentDidUpdate and componentWillUnmount did” refers to code that no longer exists.

Comment thread VideoPlayer/Video.js Outdated
preloadVideoRef.current = node;
}, []);

// Equivalent of componentDidUpdate. A layout effect keeps the class timing.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also describes the migration rather than the code. Suggest saying what the effect does and why it is a layout effect:

Comment thread VideoPlayer/Video.js Outdated
const prevProps = prevPropsRef.current;
prevPropsRef.current = {source, preloadSource};

// componentDidUpdate does not run on mount

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// skip the initial mount; only react to changes.

Comment thread VideoPlayer/Video.js Outdated
static defaultProps = {
mediaComponent: 'video'
};
const {keys, prevPreloadKey: currentPreloadKey} = keysChanged ? nextKeyState : keyState;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keysChanged ? nextKeyState : keyState isn’t needed.
When setKeyState is called during render, React throws away this render’s output and runs the component again, so the nextKeyState branch never reaches the screen.
When nothing changed, nextKeyState already holds the same values as keyState, including the same keys array. keysChanged is only needed to decide whether to call setKeyState:

Suggested change
const {keys, prevPreloadKey: currentPreloadKey} = keysChanged ? nextKeyState : keyState;
if (keysChanged) {
setKeyState(nextKeyState);
}
const {keys, prevPreloadKey: currentPreloadKey} = nextKeyState;

Comment thread VideoPlayer/Video.js Outdated
const videoRef = useRef(null);
const preloadVideoRef = useRef(null);
const preloadLoadStartRef = useRef(null);
const prevPropsRef = useRef(null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prevPropsRef keeps the whole source / preloadSource nodes, so the effect calls getKeyFromSource 4 times on every render. VideoPlayer re-renders this component often during playback. The class did the same, so this isn’t a regression, but storing the previous keys would cut it to 2 calls and drop prevSource / prevPreloadSource:

check line 114-120

`const prevKeysRef = useRef(null);
// ...
useLayoutEffect(() => {
const key = getKeyFromSource(source);
const preloadKey = getKeyFromSource(preloadSource);
const prevKeys = prevKeysRef.current;
prevKeysRef.current = {key, preloadKey};

// skip the initial mount; only react to changes
if (!prevKeys) return;

const {key: prevKey, preloadKey: prevPreloadKey} = prevKeys;
// ...

});`

Comment thread VideoPlayer/Video.js Outdated
const {keys, prevPreloadKey: currentPreloadKey} = keysChanged ? nextKeyState : keyState;

// if preload is unset, clear the key so we don't render that media node at all
const [sourceKey, preloadKey] = currentPreloadKey ? keys : keys.slice(0, 1);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are now four different “preload key” variables.
getKeys has a local preloadKey (the source key), the render has preloadKey (the slot key, 'media-1' / 'media-2'), the effect has preloadKeyFromSource, and there is currentPreloadKey.
The preloadKeyFromSource rename exists only because the render’s preloadKey clashes with the effect’s.
Renaming the slot keys makes the difference clear and lets the effect keep its natural names:

const [sourceSlotKey, preloadSlotKey] = currentPreloadKey ? keys : keys.slice(0, 1); // ... {sourceSlotKey ? (<Media ... key={sourceSlotKey} ... />) : null} {preloadSlotKey ? (<Media ... key={preloadSlotKey} ... />) : null}

Comment thread VideoPlayer/Video.js

// In the case that the previous source equalled the previous preload (causing the
// preload video node to not be created) and then the preload source was changed, we
// need to guard against accessing the preloadVideo node.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we need a test also for this scenario "Nothing tests what happens next, when preloadSource changes to a different value"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants