So I have this JSX element that I am attempting to render in the Class component. It is essentially a visual provided by D3's React library. However, I am receiving this error upon attempting to render the D3 visual:
Unhandled Rejection (Error): Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Below are some relevant code snippets of where the error is occurring:
The builder function to pass all the necessary props to the D3 library
const buildModelVisual = (dataPoints) => {
console.log("category: " + dataPoints[0].category)
console.log("range: " + dataPoints[0].range)
console.log("frequency: " + dataPoints[0].frequency)
dataPoints[0].frequency.forEach(f =>
console.log("f: " + f)
)
const width = 960,
height = 500,
margins = {top: 50, right: 50, bottom: 50, left: 50},
id = "model-visual",
title = "NaiveBayes Model Visual",
svgClassName = "model-visual-class",
titleClassName = "model-visual-title-class",
legendClassName = "model-legend",
showLegend = true,
showXAxis = true,
showYAxis = true,
showXGrid = false,
showYGrid = false,
ranges = [
...dataPoints[0].range
],
frequencies = [
...dataPoints[0].frequency
],
x = () => {
return ranges.forEach(r => {
return r;
})
},
xOrient = 'bottom',
xTickOrient = 'bottom'
const xDomain = dataPoints[0].range.forEach(r => {
return {
category: dataPoints[0].category, range: r
}
}),
xRangeRoundBands = {interval: [0, width - margins.left - margins.right], padding: 0.1},
xScale = 'ordinal',
xAxisClassName = 'x-axis',
xLabel = dataPoints[0].category,
xLabelPosition = 'bottom',
xTickPadding = 3,
xInnerTickSize = 6,
xOuterTickSize = 6,
y = () => {
return frequencies.forEach(freqInRange => {
return freqInRange.forEach(f => {
return f;
});
})
},
yOrient = 'left',
yTickOrient = 'left',
yRange = [height - margins.top - margins.bottom, 0]
const yDomain = [0, d3.max(
dataPoints[0].frequency,
(f) => {
return f.value
}
)],
yScale = 'linear',
yAxisClassName = 'y-axis',
yLabel = "Population",
yTickFormat = d3.format(".2s"),
yLabelPosition = 'left',
yTickPadding = 4,
yInnerTickSize = 6,
yOuterTickSize = 6
return (
<Chart
title={title}
id={id}
width={width}
height={height}
>
<BarStackChart
title= {title}
data= {ranges}
width= {width}
height= {height}
id= {id}
margins= {margins}
svgClassName= {svgClassName}
titleClassName= {titleClassName}
yAxisClassName= {yAxisClassName}
xAxisClassName= {xAxisClassName}
legendClassName= {legendClassName}
categoricalColors= {d3.scaleOrdinal(d3.schemeCategory10)}
chartSeries = {ranges}
showLegend= {showLegend}
showXAxis= {showXAxis}
showYAxis= {showYAxis}
x= {x}
showXGrid= {showXGrid}
xDomain= {xDomain}
xRangeRoundBands= {xRangeRoundBands}
xScale= {xScale}
xOrient= {xOrient}
xTickOrient= {xTickOrient}
xTickPadding = {xTickPadding}
xInnerTickSize = {xInnerTickSize}
xOuterTickSize = {xOuterTickSize}
xLabel = {xLabel}
xLabelPosition = {xLabelPosition}
y= {y}
showYGrid= {showYGrid}
yOrient= {yOrient}
yRange= {yRange}
yDomain= {yDomain}
yScale= {yScale}
yTickOrient= {yTickOrient}
yTickPadding = {yTickPadding}
yInnerTickSize = {yInnerTickSize}
yOuterTickSize = {yOuterTickSize}
yTickFormat= {yTickFormat}
yLabel = {yLabel}
yLabelPosition = {yLabelPosition}
/>
</Chart>
)
}
The HO class component that is rendering the graph and the interface
constructor(props) {
super(props);
this.ref = React.createRef();
this.state = {
input: "",
output: [],
visual: null
}
}
REST API call (within the default class Component) that sets the data for the BarStackChart
callGetModel = () => {
let getModelRanges = getCall(ApiURL.get_model_ranges);
let getModelFrequencies = getCall(ApiURL.get_model_frequencies);
Promise.all([getModelRanges, getModelFrequencies]).then(data => {
this.setState({output: data})
const dataPoints = [];
for (let value in JSON.parse(data[0].toString())) {
dataPoints.push({
category: value,
range: JSON.parse(data[0].toString())[value],
frequency: JSON.parse(data[1].toString())[value]
})
}
console.log(dataPoints)
const ModelVisual = buildModelVisual(dataPoints)
this.setState({ visual: ModelVisual }) // returns JSX element
console.log(this.state.visual)
});
}
The render method for the class Component
render() {
return <div>
<h3>Welcome to Naive Bayes Java!</h3>
<p>The REST API for this project is hosted at</p>
<a style={{'display':'block', 'paddingBottom':'1.5em', 'color':'rgb(0, 150, 196)'}} href="https://naivebayesjava.herokuapp.com/swagger-ui.html#/">https://naivebayesjava.herokuapp.com/</a>
<button style={{'display':'inline', 'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callListOfFiles}>
Get List of Valid Files
</button>
<button style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callGetModel}>
Get Model
</button>
<button style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callGetModelAccuracy}>
Get Model Accuracy
</button>
<div style={{'margin':'auto', 'display':'block'}}>
<input style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} type='text' value={this.state.input} onChange={this.handleChange}/>
<button style={{'background':'rgb(32, 32, 32)', 'color':'rgb(190, 190, 190)'}} onClick={this.callSetData}>
Set Training Data File
</button>
</div>
{/* <button onClick={this.callGetTrainingData}>
Get Training Data Arff Files
</button> */}
<div style={{'padding-top':'0.5em'}} ref={this.ref}></div>
<output type='textBox' style={{ 'padding':'1.25em', 'display':'block', 'Height': '30px', 'Width': '300px' }}>
{ Object.keys(this.state.output).map(key => {
return this.state.output[key]
}) }
</output>
{ this.state.visual }
</div>
}
There most definitely is a better way to implement this besides setting a "this.state.visual" JSX Element and calling that in the render method, although as I am really new to both React (started learning about a month ago) and JS (started about 3 months ago) I don't quite know all the common practices with either; just the general theory behind how they work.
This interface and my portfolio are hosted at joshuabaroni.github.io . The interface i am attempting to improve is the NaiveBayes Project Interface under the "Projects" section
Any recommendations would be appreciated! the whole JS file is available upon request.
You likely forgot to export your component from the file it's defined
in, or you might have mixed up default and named imports.
You aren't exporting your classes/functions as it is required.
Exporting without default means it's a "named export". You can have multiple named exports in a single file. So if you do this,
class Template {}
class AnotherTemplate {}
export { Template, AnotherTemplate } // named export
then you have to import these exports using their exact names. So to use these components in another file you'd have to do,
import {Template, AnotherTemplate} from './components/templates'
Alternatively if you export as the default export like this,
export default class Template {}
Then in another file you import the default export without using the {}, like this,
import Template from './components/templates'
There can only be one default export per file. In React it's a convention to export one component from a file, and to export it is as the default export.
You're free to rename the default export as you import it,
import TheTemplate from './components/templates'
And you can import default and named exports at the same time,
import Template,{AnotherTemplate} from './components/templates'
Related
This question already has answers here:
Get a CSS value from external style sheet with Javascript/jQuery
(5 answers)
Closed 1 year ago.
I have a state variable initialized like this:
const App = () => {
const [parameters, setParameters] = useState({
"shape": "circle",
"fontFamily": "",
"size": 500
});
//...
// which is here passed to a component
return(
<MyCanvas props={parameters} />
);
}
The parameters array is used by another component that renders something on the canvas. I want that the parameters is on first load of the app, at runtime, to be what's currently defined in CSS, so I want to read that CSS property and init, in this case, the "fontFamily" field with what's written in CSS. Therefore want to read the #font-face {font-family: MyLocalFont;} property from the CSS definition.
So generally: How would I read a value during runtime from a CSS for initializing the useState variable?
A compile-time solution would not meet my needs. Changes to the CSS styles can be made without re-deploying my widget, therefore I need to read the actual CSS property values during runtime upon initialization.
import React, { useCallback } from 'react';
const defaultParameters = {
"shape": "circle",
"fontFamily": "",
"size": 500,
}
const App = () => {
const [parameters, setParameters] = useState(null);
const appRoot = useCallback(
(element) => {
const style = window.getComputedStyle(element);
const fontFamily = style.getPropertyValue('font-family');
setParameters({...defaultParameters, fontFamily });
}, []
);
//...
return (
<div ref={appRoot}>
{ parameters && <MyCanvas props={parameters} /> }
</div>
);
}
You can use the 'classNames' package.
https://www.npmjs.com/package/classnames
npm install --save classnames
import classNames from 'classnames';
const Testers = () => {
const [parameters, setParameters] = React.useState({
shape: 'circle',
fontFamily: '',
size: 500,
});
//I think you can change the font name when you need it.
React.useEffect(() => {
setParameters({ ...parameters, fontFamily: 'NotoSans' });
}, []);
return (
<div className={classNames(parameters></div>
....
Also, it would be better to designate a separate font as below method.
const [fonts, setFonts] = React.useState('fontName')
const [parameters, setParameters] = React.useState({
shape: 'circle',
size: 500,
});
React.useEffect(() => {
setFonts('NotoSans');
}, []);
<div className="header">
<div className={classNames(parameters, {
fontFamily : fonts
})}></div>
I'm new to React Native, so I understand I have alot to learn.
I'm creating a custom class component here:
import React, { Component, useState } from 'react';
import {View,Text,StyleSheet,TextInput, Button} from 'react-native';
class Square extends React.Component{
constructor(pos,text,won,save){
this.state = {
pos : 0,
text : 'EDIT',
won : false,
save : false,
};
}
setPos = (pos) =>{
this.setState(pos)
}
getPos = () => {
return (this.pos);
}
setText=(text)=>{
this.setState(text)
}
getText=()=>{
return (this.text);
}
setWon=(won)=>{
this.setState(won)
}
getWon=()=>{
return (this.won);
}
setSave=(save)=>{
this.setState(save)
}
getSave=()=>{
return (this.save);
}
};
export default Square;
Then I want to create an array of those objects in a different component and display a piece of information from each object.
import {View, Text, StyleSheet, Button, Alert} from 'react-native';
import Square from '../components/Square';
const NewGameScreen = () => {
let arrSquare = [];
for (let i = 0; i < 25; i++){
arrSquare.push({
THIS IS WHERE I'M HAVING TROUBLE
});
}
console.log(arrSquare[0].getPos)
return(
<View style = {styles.screen}>
<View style = {styles.row}>
<Text>{arrSquare[0].getPos}</Text>
</View>
</View>
)
};
However from the above code I'm sure it's clear I'm missing something. I would have expected to use something like Square[i].setPos(i); but that throws errors. The console log also gives 'undefined' so that makes me think I haven't declared something or haven't declared it properly. Thanks in advance.
well the way I would go about this is to have a simple array of json object something like this:
let squareArr = [{
id: 0,
pos : 0,
text : 'EDIT',
won : false,
save : false,
},
{
id: 1,
pos : 0,
text : 'EDIT',
won : false,
save : false,
},
{
id: 2,
pos : 0,
text : 'EDIT',
won : false,
save : false,
}
]
then you can do the the read and the edit.
to display a position:
in your render method you can do this:
<View style = {styles.screen}>
<View style = {styles.row}>
squareArr.map((square) => <Text>{square.pos}</Text>)
</View>
</View>
to edit a position:
if you want to change a value in your JSON then just use the object index as a way to indicate which object you wanna change. For example want to change the pos of the second object then I would do this:
squareArr[1].pos = 3
I am not quite sure what is the whole project is to give you to give you the best solution but i hope this helps..
feel free to ask if you have any questions
I am using react js and trying to send Props from my app.js to chart.js file. When I send the hardcoded values the values are being send properly and graph is made according to it. But whenever I am passing a dynamic values, values are being passed but not used by chart.
App.js
class App extends React.Component {
state = {
text: "",
credit: [{_id:1,financeCredit:"loading"}],
debit: [{_id:1,financeDebit:"loading"}],
}
componentDidMount(){
fetch('/data')
.then(res=> res.json())
.then(res2 => {
console.log(res2)
this.setState({
credit: res2
})
})
fetch('/data2')
.then(res=> res.json())
.then(res2 => {
console.log(res2)
this.setState({
debit: res2
})
})
}
render(){
var lengthExpense = this.state.credit.length;
console.log(lengthExpense)
var expName = [];
for (var a = 0 ; a <= lengthExpense ; a++){
if (this.state.credit[a]){
expName.push(this.state.credit[a].expenseName)
}
}
var expAmount = [];
for (var b = 0 ; b <= lengthExpense ; b++){
if(this.state.credit[b])
expAmount.push(this.state.credit[b].expenseAmount)
}
console.log(expAmount)
console.log(expName)
return (
<BrowserRouter>
<div className="App">
<Navbar />
<Chart expam = {expAmount} expnam = {expName} />
<Route exact path = "/" component = {Home} />
</div>
</BrowserRouter>
);
}
}
export default App;
Although the following console.log() is showing the desired values I want to pass
console.log(expAmount)
console.log(expName)
I am passing these values like this
<Chart expam = {expAmount} expnam = {expName} />
In chart.js although I am getting these values.
Chart.js
class Chart extends Component{
constructor(props){
super(props);
this.state = {
chartData : {
labels: this.props.expnam,
datasets: [{
label: 'Expense',
data: this.props.expam,
backgroundColor:'rgba(255, 99, 132, 0.6)'
}]
}
}
}
render(){
console.log(this.props)
return(
<div className = "chart">
<div>
<Bar id = "chart1"
data={this.state.chartData}
options={{ maintainAspectRatio: false, }}
/>
<canvas id = "chart1" height="30vw" width="10vw" ></canvas>
</div>
</div>
)
}
}
But couldn't able to pass it to to labels and data. Code is properly running but there is no values so chart is being showed empty
constructor(props){
super(props);
this.state = {
chartData : {
labels: this.props.expnam,
datasets: [{
label: 'Expense',
data: this.props.expam,
backgroundColor:'rgba(255, 99, 132, 0.6)'
}]
}
}
}
In this chart.js file I can see all the values that are being passed from App.js. But these values are not been used for chart (bar chart).
console.log(this.props)
It seems like you're setting the data in your constructor:
constructor(props){
super(props);
this.state = {
chartData : {...}
}
}
A constructor is only called once when an object is initialized. (In ReactJS, it is only called after the first render.)
You are calling setState(), and the rest appears to be good, that I can tell. Why don't you move this.state = {...} from the constructor to render()? Since render() runs whenever the state is changed, your setState() calls should work.
It may be inelegant, and there can certainly be improvements, but it will get you started in the right direction.
I am trying to render the hex values in a file uploaded using react.
When I upload big files, say 10MB, the page crashes, but sites like http://mikach.github.io/hex-editor/ works like a charm. I don't understand what am I doing wrong.
Below is the code which does the same
import React from "react";
class App extends React.PureComponent {
constructor(props) {
super(props);
this.fileReader = null;
this.state = {
filecontent: [],
decodingSection: [
{ type: "BigUint64", startIndex: "0", endIndex: "0" },
{ type: "BigUint64", startIndex: "0", endIndex: "0" }
]
};
}
handleFileRead = () => {
const typedArray = new Uint8Array(this.fileReader.result);
const untypedArrray = [];
const iii = typedArray.values();
while (true) {
const { value, done } = iii.next();
if (done) {
break;
}
const hexValue = value.toString(16);
untypedArrray.push(hexValue.length === 1 ? `0${hexValue}` : hexValue);
}
this.setState({
filecontent: untypedArrray
});
};
handleFileChosen = file => {
this.fileReader = new FileReader();
this.fileReader.onloadend = this.handleFileRead;
this.fileReader.readAsArrayBuffer(file);
};
render() {
return (
<div>
<input
type={"file"}
id={"file"}
onChange={e => this.handleFileChosen(e.target.files[0])}
/>
<br />
{this.state.filecontent.length > 0 && (
<div>No Bytes present {this.state.filecontent.length}</div>
)}
{this.state.filecontent.map(each => `${each} `)}
</div>
);
}
}
export default App;
One possible cause could be the map this.state.filecontent.map(each => '${each} ') in the render method, thought I'm not sure.
I slightly modified the code, so that it saves the whole character sequence into a string called contents (using the array's join method) and then renders it at once.
You can take a look and give it a try here. At least, it worked for me on a 10Mb file :)
I am trying to create a Line Chart using React-d3 (www.reactd3.org) with both the Tooltip and Zoom components.
https://github.com/react-d3/react-d3-tooltip
https://github.com/react-d3/react-d3-zoom
However I cannot figure out how to use both components together.
I was able to create a simple LineChart:
import {LineChart} from 'react-d3-basic';
import {LineTooltip, SimpleTooltip} from 'react-d3-tooltip';
import {LineZoom} from 'react-d3-zoom';
render() {
var viewCountData = [
{
"date": new Date(2016, 5, 29),
"Object1":11,
"Object2":13,
"Object3":16
},
{
"date": new Date(2016, 5, 30),
"Object1":23,
"Object2":17,
"Object3":15
}
];
var chartSeries = [
{field: "Object1"},
{field: "Object2"},
{field: "Object3"}
];
var x = function(d) {
return d.date;
};
return (
<LineChart
data= {viewCountData}
chartSeries= {chartSeries}
x= {x}>
</LineChart>
);
}
and add Tooltips by replacing LineChart with LineTooltip:
<LineTooltip
data= {viewCountData}
chartSeries= {chartSeries}
x= {x}>
<SimpleTooltip />
</LineTooltip>
However I cannot figure out how to also use LineZoom. I tried nesting it inside LineTooltip
<LineTooltip ...>
<LineZoom ...>
</LineZoom>
</LineTooltip>
and also having both inside LineChart
<LineChart ...>
<LineTooltip ...>
</LineTooltip>
<LineZoom ...>
</LineZoom>
</LineChart>
but neither worked. Any help would be appreciated, thanks!
I basically modfified the zoom line example to include the voroni utility.
Some quick cursory tests though show there's work to be done compatibility wise, but this should help you
import React, {PropTypes} from 'react';
// import d3 from 'd3';
// import {LineZoom} from 'react-d3-zoom';
import {
Chart,
} from 'react-d3-core';
import {
LineChart,
series
} from 'react-d3-basic';
import ZoomSet from 'react-d3-zoom/lib/inherit';
import ZoomFocus from 'react-d3-zoom/lib/utils/zoom_focus';
import CommonProps from 'react-d3-zoom/lib/commonProps';
// Tooltip
import Voronoi from 'react-d3-tooltip/lib/utils/voronoi';
export default class Line extends ZoomSet {
constructor(props) {
super(props);
const {
contentTooltip,
margins,
width,
height
} = this.props;
this.zoomed = this.zoomed.bind(this);
this.mkXDomain();
this.mkYDomain();
this.state = {
xDomainSet: this.setXDomain,
yDomainSet: this.setYDomain,
onZoom: this.zoomed,
d3EventSet: null,
xRange: this.props.xRange ||
[0, width - margins.left - margins.right],
yRange: this.props.yRange ||
[height - margins.top - margins.bottom, 0],
xRangeRoundBands: this.props.xRangeRoundBands || {
interval: [0, width - margins.left - margins.right],
padding: 1
},
zoomType: 'line'
};
this.mkXScale(this.setXDomain);
this.mkYScale(this.setYDomain);
this.state = Object.assign(this.state, {
xScaleSet: this.setXScale,
yScaleSet: this.setYScale
});
}
static defaultProps = CommonProps
render() {
const {
xDomainSet,
yDomainSet,
contentTooltip
} = this.state;
const voroni = (
<Voronoi
{...this.state}
{...this.props}
// onMouseOver= {(...args)=>console.log(args)}
// onMouseOut= {(...args)=>console.log(args)}
/>
);
const focus = <ZoomFocus {...this.props} />;
// console.log('state', this.state, Chart);
return (
<div>
<Chart {...this.props} {...this.state}>
<LineChart
{...this.props}
{...this.state}
xDomain={xDomainSet} yDomain={yDomainSet}
showZoom/>
{focus}
{voroni}
</Chart>
</div>
);
}
}