What is causing infinite re-renders is that everything declared in a component function body is re-declared on every render, so buildPlay
is a new function every render, and the effect will execute infinitely. It's not really common to specify a function as a dependency (except a props.callback
maybe), but if you really want it, you should move the function out of the component and parameterize it (see show code snippet & run below).
Looking at buildPlay
, what actually changes and should be specified as dependencies in this case is [props.match.params.id, props.stream, videoRef.current]
. Your effect code should look like:
const dependencies = [props.match.params.id, props.stream, videoRef.current];
useEffect(() => {
if (!props.stream || !videoRef.current) return;
// either defined outside of component, parameterized as buildPlay(id, stream, elem)
buildPlay(...dependencies);
// or inlined in the effect
/* if(player || !props.stream){
return ;
}
var player = flv.createPlayer({
type: 'flv',
url: `http://localhost:8000/live/${id}.flv`
});
player.attachMediaElement(videoRef.current);
player.load(); */
}, dependencies);
Have a look at the 2 React apps in the snippet below: the first one takes your approach, the second one moves the dependeny function outside the component and parameterizes it.
const InfiniteRenderApp = () => {
const [runCount, setRunCount] = React.useState(0);
function doSomething() {
if (runCount < 10000) {
setRunCount(runCount + 1);
} else {
throw 'Infinite render loop. stop here!';
}
}
React.useEffect(() => {
try {
doSomething();
} catch (err) {
setRunCount(err);
}
}, [doSomething]);
return <strong>{runCount}</strong>;
};
ReactDOM.render(<InfiniteRenderApp/>, document.getElementById('infinite-render-app'));
function doSomething(runCount, setRunCount) {
setRunCount(runCount + 1);
}
const GoodApp = () => {
const [runCount, setRunCount] = React.useState(0);
React.useEffect(() => {
doSomething(runCount, setRunCount);
}, [doSomething]);
return <strong>{runCount}</strong>;
};
ReactDOM.render(<GoodApp/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
<div id="infinite-render-app"></div>
<div id="app"></div>