componentDidUpdate throwing error after being called indefinite times - reactjs

Everyone
I am trying to implement wfplayer with artplayer in my react project and came across an issue. Let me show you code first
componentDidUpdate() {
if (this.props.art && !this.wf) {
this.initWFPlayer();
}
}
where initWFPlayer() is the function which contains this.wf and its definition and
this.props.art is the state's variable storing the value of instance of artplayer.
Inside initWFPlayer()
initWFPlayer() {
const { art } = this.props;
const { $video } = art.template;
if ($video.src) {
this.wf = new WFPlayer({
container: this.$waveform.current,
mediaElement: $video,
waveColor: 'rgba(255, 235, 59, 0.95)',
progressColor: 'rgba(255, 255, 255, 0.3)',
cors: true,
scrollable:true
});
this.wf.load(this.props.pcmUrl);
}
}
where pcmUrl is the url of audio that I am getting from DB via some API.
Now, the error I am getting is
I know this issue is coming from componentDidUpdate(). I have checked that if statement is returning true/false as it should return. How can i remove it?

Related

Tradingview charting library avoid rerendering when changing state (React)

Task: create a custom replay mode using tradingview's charting library. Bars data does not come from a websocket but instead an uploaded/selected CSV.
I am trying to conditionally enable/disable subscribe bars using a state variable. When enabled it loops through the CSV and imitates a websocket to add bars every x seconds using a timeout, when paused, don't do anything.
The issue I am facing right now is, if I change the state, it re-renders the chart however I do not want to do that.
const TVChartContainer = (props) => {
const { allBars, replayBars, playing, speed } = props;
useEffect(() => {
const widgetOptions = {
debug: false,
symbol: defaultProps.symbol,
datafeed: Datafeed(allBars, replayBars, playing, speed),
interval: defaultProps.interval,
container_id: defaultProps.containerId,
library_path: defaultProps.libraryPath,
locale: getLanguageFromURL() || "en",
// disabled_features: ["use_localstorage_for_settings"],
enabled_features: ["study_templates"],
charts_storage_url: defaultProps.chartsStorageUrl,
charts_storage_api_version: defaultProps.chartsStorageApiVersion,
client_id: defaultProps.clientId,
user_id: defaultProps.userId,
fullscreen: defaultProps.fullscreen,
autosize: defaultProps.autosize,
studies_overrides: defaultProps.studiesOverrides,
data_status: "streaming",
overrides: {
"mainSeriesProperties.showCountdown": true,
"paneProperties.background": "#fff",
"paneProperties.vertGridProperties.color": "#fff",
"paneProperties.horzGridProperties.color": "#fff",
"scalesProperties.textColor": "#000",
"mainSeriesProperties.candleStyle.wickUpColor": "#2196f3",
"mainSeriesProperties.candleStyle.upColor": "#2196f3",
"mainSeriesProperties.candleStyle.borderUpColor": "#2196f3",
"mainSeriesProperties.candleStyle.wickDownColor": "#000",
"mainSeriesProperties.candleStyle.downColor": "#000",
"mainSeriesProperties.candleStyle.borderDownColor": "#000",
},
};
new widget(widgetOptions);
}, [allBars, playing, replayBars, speed]);
return <div id={defaultProps.containerId} className={"TVChartContainer"} />;
};
The playing variable is a state coming from its parent component, when changed it rerenders the chart as it initializes a new widget. Is there a workaround that? Maybe change the datafeed after it has been initialized?
Note: I do not intend to have a backend for this React app.

React-Viro AR ImageTracking sub elements are positioned inside camera when target is seen

I am currently using Viro-React (React-Viro) for a AR project in which, if a certain pictures gets seen by the camera a video is played infront of it. I had it working perfectly, but somehow and a few days later, without changing the code, the video and everything inside the ViroARImageMarker is always positioned inside the camera, when the target gets seen.
This behavior only seems to happen in my own projects and not in the samples provided by Viro Media.
I have tried to:
Reinstalling node modules
Compared the package.json's and reinstalled.
Changed the position of the elements inside the ViroARImageMarker
And reorganised the elements.
But nothing seems to work.
As I said the code itself shows and hides the video, but does not position the video (every inside the ViroARImageMarker correctly, but positions them in the position of the camera when the targets gets seen and then keeps them there.
Here is the code. (Snippet at the end)
I pass this function to the ViroARSceneNavigator in another script.
There are a few animations, which just scale up/down the video depending if the target is in view or not.
(I removed the whitespaces to fit more onto one screen)
Main Code
Viro Animations and Material
"use strict";
import React, { useState } from "react";
import { ViroARScene, ViroNode, ViroARImageMarker, ViroVideo, ViroARTrackingTargets, ViroAnimations, ViroMaterials } from "react-viro";
const MainScene = (props) => {
const videoPath = require("./res/Test_Video.mp4");
const [playVideoAnimation, setPlayVideoAnimation] = useState(false);
const [videoAnimationName, setVideoAnimationString] = useState("showVideo");
const [shouldPlayVideo, setShouldPlayVideo] = useState(false);
function onAnchorFound() {
setPlayVideoAnimation(true);
setVideoAnimationString("showVideo");
setShouldPlayVideo(true);
}
function onAnchorRemoved() {
setShouldPlayVideo(false);
setVideoAnimationString("closeVideo");
setPlayVideoAnimation(true);
}
function onVideoAnimationFinish() {
setPlayVideoAnimation(false);
}
function onVideoFinish() {
setShouldPlayVideo(false);
setVideoAnimationString("closeVideo");
setPlayVideoAnimation(true);
}
return (
<ViroARScene>
<ViroARImageMarker target={"targetOne"} onAnchorFound={onAnchorFound} onAnchorRemoved={onAnchorRemoved}>
<ViroNode rotation={[-90, 0, 0]}>
<ViroVideo
position={[0, 0, 0]}
scale={[0, 0, 0]}
dragType="FixedToWorld"
animation={{ name: videoAnimationName, run: playVideoAnimation, onFinish: onVideoAnimationFinish }}
source={videoPath}
materials={["chromaKeyFilteredVideo"]}
height={0.2 * (9 / 16)}
width={0.2}
paused={!shouldPlayVideo}
onFinish={onVideoFinish}
/>
</ViroNode>
</ViroARImageMarker>
</ViroARScene>
);
};
ViroAnimations.registerAnimations({
showVideo: {
properties: { scaleX: 0.9, scaleY: 0.9, scaleZ: 0.9 },
duration: 1,
easing: "bounce",
},
closeVideo: {
properties: { scaleX: 0, scaleY: 0, scaleZ: 0 },
duration: 1,
},
});
ViroMaterials.createMaterials({
chromaKeyFilteredVideo: {
chromaKeyFilteringColor: "#00FF00",
},
});
ViroARTrackingTargets.createTargets({
targetOne: {
source: require("./res/Test_Bild.png"),
orientation: "Up",
physicalWidth: 0.01, // real world width in meters
},
});
export default MainScene;
I was able to resolve the issue by copying (downgrading) my dependencies in my package.json from the React-Viro codesamples and decreasing the width/height (inside the element) and scale (in the animation) of the video.
Note that if the sub element of the ViroARImageMarker is too big (in scale and size), the issue comes back.

Chart is not displaying updated data

I have used https://www.npmjs.com/package/react-chartjs-2, and it displays a chart with data in the first time. But whenever I try to redraw, using new data and datasets it always displays previous graph data on a chart.
I have tried solutions from: https://github.com/reactchartjs/react-chartjs-2
Also tried to give reference
But still, it shows the same data which it loads the first time.
Code to display chart,
<Line
data={graphData}
redraw
options={options}
height="100px"
weight="100px"
/>
In this,
graphData is,
const [graphData, setGraphData] = useState(data);
redraw,
I have also tried to do, redraw={true}
When the data will be modified, I use setGraphData(updatedData) to update the chart, I have also checked whether data is changed or not.
Data in graphData updates but not displayed on graph
Where the data which is assign as a default data for graphData,
const data = {
labels: months,
datasets: [
{
label: "# of Users",
data: [0, 64, 129, 193, 258, 322, 387, 451, 516, 580],
fill: false,
backgroundColor: "rgb(255, 99, 132)",
borderColor: "rgba(255, 99, 132, 0.2)",
yAxisID: "y-axis-1",
},
{
label: "# of Orders",
data: [0, 25, 50, 76, 101, 126, 151, 177, 202, 227],
fill: false,
backgroundColor: "rgb(54, 162, 235)",
borderColor: "rgba(54, 162, 235, 0.2)",
yAxisID: "y-axis-2",
},
],
};
I am creating copy of this data and then assigning in setGraphData()
Anyone can Help me with this! Thank you in advance!!
Without seeing the code, there is only one solution here. Provide a key to the chart component & update the key once the data is updated,
<chart key={getKey()} data={data} />
The get key will create a unique key with respect to the new data.
const getKey = () => {
return data?.map((p) => p.id)?.join();
};
The only thing important here is that the getKey method should return a new value if the data is updated JSON.stringify(data) is the simplest option(I am not sure if it is a good approach to provide the serialized data as key, but surely it will work)
The issue behind re-rendering was a function defined to call, backend API handler and assigning data to the Line chart.
Before - not working
useEffect(() => {
...
the function which has code to call and fetch data from back-end API/handler
}, []);
After - working
useEffect(() => {
...
Code which calls back-end API/handler function to fetch data for graph
...
}, []);
I have also keep redraw,
<Line
key={JSON.stringify(graphData)}
data={graphData}
redraw
options={options}
height="100px"
weight="100px"
/>
Stumbled upon this answer while struggling with this issue. Essentially you have to deep clone the data when copying and mutating any values. Works great because you don't need to set redraw which causes the jittery animation.

Mapbox layer not updating after source update

I'm using Redux state to update an array of coordinates in a Mapbox source. I initially check if there is a source with the id, if yes, I set the data of the source, if not I add the source to the map. When the redux state is changed, it triggers an effect which updates the coordinates of the features in the geojson object and uses setData to change the source. I've tried removing the layer, changing source and adding the layer, which just gave me the old layer (even though the source had indeed been updated). I also tried just updating the source alone and seeing if the layer would update dynamically, it did not.
Here is the code for the effect, which is triggered when the redux state is changed.
useEffect(() => {
const geoJsonObj = {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: []
}
};
for (let i = 0; i < (props.mapRoutes.length); i++) {
geoJsonObj.data.features.push({
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: props.mapRoutes[i].geometry.coordinates
}
});
};
const routeLayer = {
id: 'route',
type: 'line',
source: 'route',
layout: {
'line-join': 'round',
'line-cap': 'round'
},
paint: {
'line-color': '#ff3814',
'line-width': 5,
'line-opacity': 0.75
}
};
const jsonString = JSON.stringify(geoJsonObj);
const jsonObj = JSON.parse(jsonString);
if (props.mapRoutes.length) {
if (map.current.getSource('route')) {
map.current.getSource('route').setData(jsonObj);
} else {
map.current.addSource('route', jsonObj);
map.current.addLayer(routeLayer);
};
};
}, [props.mapRoutes]);
Neither of these worked and I am having trouble finding how to update a layer based on an updated source. Everything seems right when I inspect the source in the console, I just can't manage to update the layer on the map.
Any help would be appreciated.
I found the problem, I was using the original geoJson object for the setData method instead of the data entry, which was one level too high in the object. Just a simple error which was overlooked.

Using setState() to set more complex data

what im trying to achieve is to be able to use the setState method to set an object as the state. However im facing some difficulty in doing so.
This is the final endproduct (state) which i was to achieve
state_class_mapping: {
{1} ,
rect: {
fill: "deepskyblue"
},
label: {
stroke: "white"
}
This values are obtained from different areas , the rect and label is preset in my state upon initializing:
constructor(props) {
super(props)
this.state = {
selected_state: null,
state_class_mapping: {},
selected_state_class: { #<---- here
rect: {
fill: "deepskyblue"
},
label: {
stroke: "white"
}
},
default_state_class: { #<---- or here depending
rect: {
fill: "#dddd"
},
label: {
stroke: "black"
}
}
}
The integer value is actually the ID of the object that i have clicked . Upon clicking onto this object , i would run some functions to set the "selected_state" .
My issue is that i have issues creating the state_class_mapping state as its more complex than just setting a static key and value.
What i would envision the way to set would be :
this.setState({state_class_mapping:{
{this.state.selected_state},
{this.state.default_state_class}
})
}
}
But ofcourse my editor shows that it is illegal to do it this way. May i know what is the proper way of doing this?
I just looked at your code and I think you missed some snippets.
First you need to declare correct object according to exact type you declared in state definition.
So in my opinion you need to try like this.
this.setState({state_class_mapping: {
idValue,
...this.state.selected_state,
...this.state.default_state_class
}});
You didn't declare state_class_mapping type as { {}, [{}]} so your code isn't working.
You declared as this type {{}, {}}
Hope this helps you to understand.

Resources