How to call function from function array (React js) - javascript

I Created array that contains functions and now I am trying to call a function from that array, I tried this code but it's not working and I have no idea how can I do it becuase I am pretty new at react js. Can someone help me with this?
here is my code
import React, { Component } from "react";
import "../App.css";
export default class Chart extends Component {
constructor(props) {
super(props);
this.state = {
stockChartXValues: "",
stockChartYValues: "",
type: props.data,
};
}
getBTC = () => {
// .....
};
getETH = () => {
// .....
};
getADA = () => {
// .....
};
componentDidMount() {
// here I am trying to run a function according to the "type" variable
var options = ["BTC", "ETH", "ADA"];
var functions = [this.getBTC, this.getETH, this.getADA];
var func = functions.indexOf(options.indexOf(this.state.type));
func.call();
}
render() {
return (
<div>
<h1>Hello world</h1>
</div>
);
}
}

you need to get function with the index you found;
var func = functions.indexOf(options.indexOf(this.state.type));// this returns index not the actual func
functions[func] && functions[func]()
My Approach would be like;
getBTC = () => {
// .....
};
getETH = () => {
// .....
};
getADA = () => {
// .....
};
getCoin = (type) => {
switch(type) {
case "BTC": this.getBTC()
return
case "ADA":...
...
...
}
componentDidMount() {
this.getCoin(this.state.type)
}

Related

React component don't update the state properly with fetched data

I have these two components: I fetch the data in the parent component and then pass it to the child component, which formats it into an object so that it can be used in the construction of a graph.
When the child component is mounted for the first time, the graph is not rendered.
If I try to change the child component code to update it (e.g. delete linkColor from ForceGraph2D’s props), the graph will be displayed correctly.
I want to find a way to see it right away, the first time the component is mounted.
Parent component:
import React, {Fragment, useEffect, useState} from "react";
import AddressList from "./AddressList";
import ClusterGraph from "./ClusterGraph";
import axios from "axios";
function ClusterPage(props) {
const [cluster, setCluster] = useState([]);
const [subCluster, setSubCluster] = useState([]);
useEffect(() => {
fetchData1();
fetchData2();
},[]);
const fetchData1 = async () => {
const address = props.match.params.addressHash;
const response = await axios.get('http://localhost:5000/', {
params: {address: address}
});
const data = await response.data;
setCluster(data);
}
const fetchData2 = async () => {
const address = props.match.params.addressHash;
const response = await axios.get('http://localhost:5000/sub/', {
params: {address: address}
});
const data = await response.data;
setSubCluster(data);
}
return (
<div key={props.match.params.id}>
<Fragment>
<AddressList data={cluster} />
<ClusterGraph data1={cluster} data2={subCluster} />
</Fragment>
</div>
);
}
export default ClusterPage;
Child component:
import '../styles/ClusterGraph.css';
import ForceGraph2D from 'react-force-graph-2d';
import React from "react";
class MyClusterGraph extends React.Component {
constructor(props) {
super(props);
this.state = {nodes:[],links:[]};
}
componentWillMount() {
this.loadData();
}
loadData = async () => {
let nodes = this.props.data1.map(row => {
let id = row.address_id;
let addressHash = row.address_hash;
let nodeColor;
if(row.miner_address)
nodeColor="blue";
else
nodeColor="purple";
return {id:id,addressHash:addressHash,nodeColor:nodeColor};
});
let links = this.props.data2.map(row => {
let source = row.address_id_1;
let target = row.address_id_2;
let linkColor;
switch (row.link_type) {
case 0:
linkColor="green";
break;
case 1:
linkColor="red";
break;
case 2:
linkColor="cyan";
break;
}
return {source:source,target:target,linkColor:linkColor};
});
this.setState({nodes:nodes,links:links});
}
render() {
return (
<div className="graph">
<ForceGraph2D
graphData={this.state}
backgroundColor="white"
height={400}
width={700}
nodeLabel="addressHash"
nodeColor="nodeColor"
linkColor="linkColor" />
</div>
);
}
}
function ClusterGraph({data1,data2}) {
return (
<div className="section2">
<MyClusterGraph data1={data1} data2={data2} />
</div>
);
}
export default ClusterGraph;
You could make sure you render your graphs after the data is fully fetched, and show a loader in the meantime, like so:
function ClusterPage(props) {
const [cluster, setCluster] = useState([]);
const [subCluster, setSubCluster] = useState([]);
useEffect(() => {
fetchData1();
fetchData2();
}, []);
const fetchData1 = async () => {
const address = props.match.params.addressHash;
const response = await axios.get("http://localhost:5000/", {
params: { address: address },
});
const data = await response.data;
setCluster(data);
};
const fetchData2 = async () => {
const address = props.match.params.addressHash;
const response = await axios.get("http://localhost:5000/sub/", {
params: { address: address },
});
const data = await response.data;
setSubCluster(data);
};
if (cluster.length <= 0 || subCluster.length <= 0) {
return <p>Loading...</p>;
}
return (
<div key={props.match.params.id}>
<Fragment>
<AddressList data={cluster} />
<ClusterGraph data1={cluster} data2={subCluster} />
</Fragment>
</div>
);
}
This way, you would use the constructor to format your data, as componentWillMount() is deprecated and considered unsafe:
class MyClusterGraph extends React.Component {
constructor(props) {
super(props);
this.state = {
nodes: this.props.data1.map((row) => {
let id = row.address_id;
let addressHash = row.address_hash;
let nodeColor;
if (row.miner_address) nodeColor = "blue";
else nodeColor = "purple";
return { id: id, addressHash: addressHash, nodeColor: nodeColor };
}),
links: this.props.data2.map((row) => {
let source = row.address_id_1;
let target = row.address_id_2;
let linkColor;
switch (row.link_type) {
case 0:
linkColor = "green";
break;
case 1:
linkColor = "red";
break;
case 2:
linkColor = "cyan";
break;
}
return { source: source, target: target, linkColor: linkColor };
}),
};
}
render() {
return (
<div className="graph">
<ForceGraph2D
graphData={this.state}
backgroundColor="white"
height={400}
width={700}
nodeLabel="addressHash"
nodeColor="nodeColor"
linkColor="linkColor"
/>
</div>
);
}
}
function ClusterGraph({ data1, data2 }) {
return (
<div className="section2">
<MyClusterGraph data1={data1} data2={data2} />
</div>
);
}
export default ClusterGraph;
Try making your parent component calls synchronous currently it is sync individually but it calls in async fashion change your code base accordingly

VueJs How to call a modal once a day?

Good afternoon) Help please. How to make the modal pop up once a day when the site loads. I have 2 options with localstorage and cookie, but I don't know how to make the logic correct.
project link
https://codesandbox.io/s/kind-torvalds-e315y?file=/src/App.vue:2283-2284
hey I think this should work
// modalService.js
const STORAGE_KEY = "LS_LAST_UPDATE";
const getStorageValue = () => {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY));
} catch {
return "";
}
};
const setStorageValue = (value = "") =>
localStorage.setItem(STORAGE_KEY, JSON.stringify(value));
const dateIsOld = () => {
const today = new Date().toLocaleDateString();
return getStorageValue() !== today;
};
const updateDate = () => {
setStorageValue(new Date().toLocaleDateString());
};
export { dateIsOld, updateDate };
export default {
dateIsOld,
updateDate,
};
and in your vue component you do something like this
import { dateIsOld, updateDate } from "./path/to/modalService.js"
export default {
name: "App",
data() {
return {
showModal: false,
};
},
mounted() {
//this.runModalTimer()
this.showModal = dateIsOld()
},
methods: {
close() {
this.showModal = false;
updateDate()
},
};
}

How to query in firebase database in react?

I have the following data structure in firebase as a realtime database:
{
"react" : {
"url_01" : "https://stackoverflow.com/",
"url_02" : "https://google.com/",
"url_03" : "https://www.youtube.com/"
}
}
I'm trying to query the database in React to display all URLs in the below component.
So far I got it to display the first URL in the database correctly but now trying to display them all in the div as <h1>.
class FirebaseDB extends React.Component {
constructor() {
super();
this.state = {
speed: [],
};
}
componentDidMount() {
const rootRef = firebase.database().ref().child('react');
const speedRef = rootRef.child('url_01');
speedRef.on('value', snap => {
this.setState({
speed: snap.val()
});
});
}
render() {
return (
<div>
<h1>URL: {this.state.speed}</h1>
</div>
);
}
}
componentDidMount() {
const rootRef = firebase.database().ref();
const speedRef = rootRef.child('react');
speedRef.once("value", snap => {
// Handle state
let speedsUrls = []
snap.forEach(child => {
speedsUrls.push(child.val())
});
this.setState({speed: speedsUrls})
});
}
render() {
const SpeedURLS = this.state.speed.map(url => <h1>URL: {url}</h1>);
return (
<div>
{SpeedURLS}
</div>
);
}
Another solution:
const object1 = {
"url_01" : "https://stackoverflow.com/",
"url_02" : "https://google.com/",
"url_03" : "https://www.youtube.com/"
};
let a = Object.values(object1);
a is now
["https://stackoverflow.com/","https://google.com/","https://www.youtube.com/"]

Call a callback each time state changes in React [duplicate]

This question already has answers here:
Why is setState in reactjs Async instead of Sync?
(8 answers)
Closed 5 years ago.
I have an app like:
Main.js-
import React, { Component } from 'react';
import _ from 'underscore';
import { pick_attributes } from '../utils/general';
import ApplicationsButtons from '../components/ApplicationsButtons';
import Roles from '../components/Roles';
let applications_url = 'http://127.0.0.1:8889/api/applications'
export default class Main extends Component {
constructor(props) {
super(props);
this.state = {
applications: [],
selected_app_id: 1,
roles: []
};
this.updateSelectedApp = this.updateSelectedApp.bind(this);
this.updateApplicationData = this.updateApplicationData.bind(this);
this.loadAppData = this.loadAppData.bind(this);
this.getSelectedApplicationData = this.getSelectedApplicationData.bind(this);
this.setRoles = this.setRoles.bind(this);
}
componentDidMount() {
this.loadAppData();
}
// componentDidUpdate() {
// this.updateApplicationData();
// }
updateApplicationData() {
this.setRoles();
}
loadAppData() {
let self = this;
$.ajax({
url: applications_url,
method: 'GET',
success: function(data) {
let objects = data.objects;
self.setState({applications_data: objects});
let apps_data = pick_attributes(objects, 'name', 'id');
self.setState({applications: apps_data});
self.updateApplicationData();
}
});
}
getSelectedApplicationData() {
let selected_app_id = this.state.selected_app_id;
let objects = this.state.applications_data;
for (let i = 0; i < objects.length; i++) {
let object = objects[i];
if (object.id == selected_app_id) {
return object
}
}
}
setRoles() {
let selected_app_id = this.state.selected_app_id;
let selected_app_object = this.getSelectedApplicationData();
let roles_data = selected_app_object.role_list;
let roles = pick_attributes(roles_data, 'name', 'id');
this.setState({roles});
}
updateSelectedApp(id) {
this.setState({selected_app_id: id});
}
render() {
return (
<div>
{this.state.selected_app_id}
<ApplicationsButtons
apps={this.state.applications}
clickHandler={this.updateSelectedApp}/>
<Roles roles={this.state.roles} />
</div>
);
}
}
ApplicationsButtons.js-
import React, { Component } from 'react';
export default class ApplicationsButtons extends Component {
render() {
var buttons = null;
let apps = this.props.apps;
let clickHandler = this.props.clickHandler;
if (apps.length > 0) {
buttons = apps.map(function(app) {
return (
<button
onClick={() => clickHandler(app.id)}
key={app.id}>
{app.name} - {app.id}
</button>
);
});
}
return (
<div>
{buttons}
</div>
);
}
}
Roles.js-
import React, { Component } from 'react';
export default class Roles extends Component {
render() {
var roles_li_elements = null;
let roles = this.props.roles;
console.log(roles);
if (roles.length > 0) {
roles_li_elements = roles.map(function(role) {
console.log(role);
return (
<li key={role.id}>
{role.name}
</li>
);
});
}
return (
<div>
<h4>Roles:</h4>
<ul>
{roles_li_elements}
</ul>
</div>
);
}
}
I want the Roles to update when the user clicks a button that picks a new app. Right now, clicking the buttons does update state.selected_app_id, but I need setRoles() to be called each time selected_app_id changes. I tried throwing it in the onClick:
updateSelectedApp(id) {
this.setState({selected_app_id: id});
this.setRoles();
}
for some reason that only changed the roles after clicking each button twice.
componentDidUpdate() {
this.updateApplicationData();
}
causes state to update forever in an infinite loop. You aren't supposed to update state inside componentWillUpdate.
updateSelectedApp(id) {
this.setState({selected_app_id: id}, () => {
this.setRoles();
});
}

Pass state updater clickHandler in React

I have a React app like:
Main.js-
import React, { Component } from 'react';
import _ from 'underscore';
import ApplicationsButtons from '../components/ApplicationsButtons';
let applications_url = 'http://127.0.0.1:8889/api/applications'
export default class Main extends Component {
constructor(props) {
super(props);
this.state = {applications: [], selected_app: 1};
this.updateSelectedApp = this.updateSelectedApp.bind(this);
}
componentDidMount() {
let self = this;
$.ajax({
url: applications_url,
method: 'GET',
success: function(data) {
console.log(data);
let objects = data.objects;
let apps = objects.map(function(object) {
return {name: object.name, id: object.id};
});
console.log(apps);
self.setState({applications: apps});
}
});
}
updateSelectedApp(id) {
this.setState({selected_app: id});
}
render() {
return (
<div>
{this.state.selected_app}
<ApplicationsButtons apps={this.state.applications} />
</div>
);
}
}
ApplicationsButtons.js-
import React, { Component } from 'react';
export default class ApplicationsButtons extends Component {
render() {
var buttons = null;
let apps = this.props.apps;
let clickHandler = this.props.clickHandler;
if (apps.length > 0) {
buttons = apps.map(function(app) {
return (<button key={app.id}>{app.name} - {app.id}</button>);
// return (<button onClick={clickHandler.apply(null, app.id)} key={app.id}>{app.name} - {app.id}</button>);
});
}
return (
<div>
{buttons}
</div>
);
}
}
I want to pass an onClick to the buttons that will change the currently selected app. Somehow, I just got my first infinite loop in React ("setState has just ran 20000 times"). Apparently, when I tried to pass the event handler to be called on click, I told it to keep calling it.
The onClick function should change state.selected_app for the Main component, based on the id for the button that was clicked.
You are not passing the handler as prop.
Here's what you should do:
render() {
return (
<div>
{this.state.selected_app}
<ApplicationsButtons
apps={this.state.applications}
handleClick={this.updateSelectedApp}
/>
</div>
);
}
And in ApplicationButtons:
render() {
var buttons = null;
let apps = this.props.apps;
let clickHandler = this.props.handleClick;
if (apps.length > 0) {
buttons = apps.map(app =>
<button key={app.id} onClick={() => clickHandler(app.id)}>{app.name} - {app.id}</button>);
);
}
return (
<div>
{buttons}
</div>
);
}

Categories