Hello I am following a tutorial on learning React and right out of the gate am getting a undefined reference error. I am calling all the dependent libraries locally so I don't think it is a problem with hte libraries not fully loading. I am a newbie to React so I'm not sure what the issue is
I tried renaming the variables and looked through all the similar issues with reference errors posted here
<div id="entry-point"></div>
<script src="lib/react.js"></script>
<script src="lib/react-dom.js"></script>
<script src="lib/babel.js"></script>
<script>
console.log('notes')
let notes = [
{ id: 1, content: "Learn React" },
{ id: 2, content: "Get Lunch" },
{ id: 3, content: "Learn React Native" }
]
class Note extends React.Component {
render() {
return React.createElement("li", {}, this.props.content)
}
}
class NotesList extends React.Component {
renderNote(note) {
return React.createElement(Note, { key: note.id, content: note.content })
}
render() {
let { notes } = this.props
return React.createElement("ul", {}, notes.map(this.renderNote, this))
}
}
class App extends React.Component {
render() {
let { notes } = notes
return React.createElement(
"section",
{},
React.createElement("h1", {}, "You have ", notes.length, " notes"),
React.createElement(NotesList, { notes: notes })
)
}
}
ReactDOM.render(
React.createElement(App, { notes: notes }),
document.getElementById("entry-point")
)
</script>
This is the error message I'm getting:
ReferenceError: Cannot access 'notes' before initialization
at App.render (scratch.html:47)
at h (react-dom.js:130)
at beginWork (react-dom.js:134)
at d (react-dom.js:158)
at f (react-dom.js:159)
at g (react-dom.js:159)
at t (react-dom.js:167)
at x (react-dom.js:166)
at r (react-dom.js:164)
at v (react-dom.js:163)
ReferenceError: Cannot access 'notes' before initialization
at App.render (scratch.html:47)
So your compiler is telling you where your problem is, in this case line 47 inside your render function.
Then it is telling you that it cannot access before initialization. You are attempting to destructure with this syntax:
let { notes } = notes
This is essentially saying "let notes = notes.notes;" Since notes is an array and doesn't have a property called notes - you are receiving an error. You already have notes defined in the scope, so try deleting that line and seeing what happens.
Related
So, the following implementation works just fine to read JSON data and turn it into rendered components - until I try to add the children. Then, it spits out an error.
function:
const catalogRenderer = (config) => {
if (typeof KeysToComponentMap[config.component] !== "undefined") {
return React.createElement(
KeysToComponentMap[config.component],
{
key: config.key,
title: config.title
},
{
config.children && config.children.map(c => catalogRenderer(c))
}
);
}
}
error:
app.js:134 Uncaught Error: Module build failed (from ./node_modules/babel-loader/lib/index.js)
"...Scripts/CatalogRenderer.js: Unexpected token, expected "," (25:14)"
console:
},
24 | {
> 25 | config.children && config.children.map(c => catalogRenderer(c))
| ^
26 | }
27 | );
28 | }
I'm using react as part of an electron application, it's a long story about all the moving parts, but everything else so far has worked just fine. In the editor, if I move to the preceding { from that mysteriously disliked . on line 25, it's highlighting the period as if this should somehow close the bracket.
Is there something I'm not understanding about the syntax here? The same thing happens if I attempt to just map and render the children like so:
{
config.children.map(c => catalogRenderer(c))
}
I've tried enclosing the whole statement in brackets, curly braces, parentheses--no matter what I do, babel seems to expect a comma, but giving it a comma obviously doesn't help. Any idea what I'm doing wrong?
eta: This is the JSON object I'm attempting to render from:
const catConfig = {
catalog: [
{
component: 'pen',
title: `B.C. Palmer`,
key: `B.C.PalmerPen`,
children: `A child string`
},
{
component: 'content',
key: `B.C.PalmerWorldList`,
children: [
{
component: 'world',
title: `Rismere`,
key: `RismereWorld`
},
{
component: 'content',
key: `RismereSeries`,
children: [
{
component: 'series',
title: `The Eidolon War`,
key: `TheEidolonWarSeries`
},
{
component: 'content',
key: `TheEidolonWarBooks`,
children: [
{
component: 'book',
title: `Magic's Heart`,
key: `MagicsHeartBook`
},
{
component: 'book',
title: `Magic's Fury`,
key: `MagicsFuryBook`
},
{
component: 'book',
title: `Magic's Grace`,
key: `MagicsGraceBook`
}
]
}
]
}
]
},
{
component: 'pen',
title: `Simon Strange`,
key: `SimonStrangePen`
}
]
}
This JSON will be generated via a database call, and written each time the database is updated, and update the state of the 'catalog' component.
So, for example, the second object in the catalog array above is a container which, when the first 'pen' component is clicked, becomes visible and shows a list of 'world' components (in this case, just the one.) However, the function only successfully renders any 'parent' components--if I take out the curly braces at lines 24 and 26, it simply skips them but doesn't error.
The components are composed of button elements and a div (content). The buttons will likely become Link element when I get this working, but the original version was written in vanilla javascript, I haven't implemented routing with the catalog yet. So, the pen component for example:
import React from 'react'
export default penButton => {
return(
<button className="catalogItem pen">
<img src="src/icons/catPenName.png" className="catalogIcon"/>
<p className="contentLabel">{penButton.title}</p>
</button>
)
}
Is a top level component, and gets rendered just fine. It's next sibling (and the next sibling of any button except a book) is content:
import React from 'react'
export default contentList => {
return(
<div className="contentList">
</div>
)
}
contentList is just a div with the contentList class, which handles visibility and animation. Should I have a place for the "children" key in JSON to populate the children of content?
When you want to render multipile children elemen'ts into your react component, you need to pass each child as a seperate parameter.
See this answer as an example:
how to render multiple children without JSX
so your solution should be to use spread syntax.
here is an example:
const catalogRenderer = (config) => {
if (typeof KeysToComponentMap[config.component] !== "undefined") {
let childs = [];
if (config.children) {
childs = config.children.map(c => catalogRenderer(c));
}
return React.createElement(
KeysToComponentMap[config.component],
{
key: config.key,
title: config.title
},
...childs
);
}
}
Well, that was simple and a little silly. I updated the content component to:
import React from 'react'
export default contentList => {
return(
<div className="contentList">
{contentList.children} <---- added
</div>
)
}
Content didn't have a place to put children. Obviously.
I am trying to test a vue component that uses this.$parents.props in it.
e.g.
export default class item extends Vue {
private point = this.$parent.$props.point;
}
The reason why I think I need to mock this.$parents.$props is because I get an error like this.
TypeError: Cannot read property 'point' of undefined
I have tried mounting options, parentComponent, but it throws an error saying "[vue-test-utils]: options.parentComponent should be a valid Vue component options object".
This is the code I used for testing.
import Parent from "#/components/Parent.vue";
let wrapper: any;
describe("item.vue", () => {
it("item vue testing", () => {
wrapper = mount(item, {
propsData: {
num: 1,
},
parentComponent: Parent
});
});
});
What should I do to mock this.$parent.$props? What is the mistake in the above test code?
you can mock like that
describe("item.vue", () => {
it("item vue testing", () => {
wrapper = mount(item, {
propsData: {
num: 1,
},
parentComponent: Parent
});
//with functions
wrapper.vm.$parent= jest.fn().mockResolvedValue("return")
//or property
wrapper.vm.$parent.$props.point = "value"
});
});
Ok so I have the following prop that I get from the parent component
props: {
selectedExchange: {
default: 'acx',
}
},
And i try to use it in the following method
methods: {
getMarkets() {
const ccxt = require('ccxt')
const exchanges = ccxt.exchanges;
let marketPair = new ccxt[this.selectedExchange]()
let markets = marketPair.load_markets()
return markets
}
},
The expected result should be an array of markets for my project but i get an error in the console
[Vue warn]: Error in mounted hook: "TypeError: ccxt[this.selectedExchange] is not a constructor"
Now i thought it might be a problem with ccxt but it's not! I have tried the following code
methods: {
getMarkets() {
const ccxt = require('ccxt')
const exchanges = ccxt.exchanges;
let acx = 'acx'
let marketPair = new ccxt[acx]()
let markets = marketPair.load_markets()
return markets
}
},
If you don't see the change I have made a variable that contains 'acx' inside, exactly the same like the prop but this time it's created inside the method, and with this code I get the expected result, It has been bugging me for days and I can't seem to find an answer to it, did I initialize the default value wrong? When i look inside vue dev tools the value for my prop is array[0], only after I pass a value to that prop it gets updated, shouldn't i see the default value of acx in devtools? Any help is much appreciated!
Edit 1: Added parent component code
This is how i use the methods inside the parent and how my components are related to each other,
<div id="exchange">
<exchange v-on:returnExchange="updateExchange($event)"></exchange>
</div>
<div id="pair">
<pair :selectedExchange="this.selectedExchange"></pair>
</div>
And this is the code inside the script tags, i didn't include the import tag cause i don't think it would be useful
export default {
name: 'App',
components: { exchange, pair, trades },
data(){
return{
selectedExchange: ''
}
},
methods: {
updateExchange(updatedExchange){
this.selectedExchange = updatedExchange
}
},
};
In this case you will inherit the default value:
<pair></pair>
In this case you will always inherit the value of selectedExchange, even if it's null or undefined:
<pair :selectedExchange="this.selectedExchange"></pair>
So, in your case, you have to handle the default value on parent component.
This should work:
export default {
name: 'App',
components: { exchange, pair, trades },
data(){
return{
selectedExchange: 'acx' // default value
}
},
methods: {
updateExchange(updatedExchange){
this.selectedExchange = updatedExchange
}
},
};
I installed the package react-treebeard
https://react.rocks/example/react-treebeard
To allow me to have a nice out of the box tree control for my React TS website which allowed searching etc. The online demo all works fine, however it is in ReactJS so there are some modifications I have had to make to translate it to TS syntax. However there are two problems
1) When I click on a node, it crashes out with
TypeError: Cannot read property 'cursor' of null
Content../src/Content.tsx.Content.onToggle
C:/src/investment/src/signoff/src/Content.tsx:94
91 | // } 92 | 93 | private onToggle(node: any, toggled: any) {
94 | const {cursor} = this.state; 95 | if (cursor) { cursor.active = false; } 96 | 97 | node.active = true;
and
2) The tabbing and indenting of the tree nodes is wrong - I assume I've not included some styling component somewhere but can't see what as I would have thought it was all in the node module package downloaded by npm install react-treebeard
The second one is less an issue as I can work through that, I just mentioned it in case something glaring jumps out. However the first one seems to be a basic problem with me not converting it to TS syntax correctly so hoping someone can spot the issue.
My component
import * as React from 'react';
import './App.css';
import {Treebeard} from 'react-treebeard';
import data from './components/treebeard/data';
interface IContentState {
data : any,
cursor : any
}
class Content extends React.Component<{},IContentState> {
constructor(props: any) {
super(props);
this.setState({cursor: null});
this.setState({data: data});
this.onToggle = this.onToggle.bind(this);
}
public render() {
const stateData = {
children: [
{
children: [
{ name: 'child1' },
{ name: 'child2' }
],
name: 'parent',
},
{
children: [],
loading: true,
name: 'loading parent',
},
{
children: [
{
children: [
{ name: 'nested child 1' },
{ name: 'nested child 2' }
],
name: 'nested parent',
}
],
name: 'parent',
}
],
name: 'root',
toggled: true,
};
return (
<div className="Center-content">
<div className="Tree-control">
<Treebeard data={stateData}
onToggle={this.onToggle}/>
</div>
</div>
);
}
private onToggle(node: any, toggled: any) {
const {cursor} = this.state;
if (cursor) { cursor.active = false; }
node.active = true;
if (node.children) { node.toggled = toggled; }
this.setState({cursor: node});
}
}
export default Content;
You setState the value of cursor: null, change it to true or false, null values always cause unexpected crashes. You should avoid putting null values on your components also I think you were trying to have this this.state = { cursor: null }
As far I can see you have no state
I am using ReactDOM.render() to render a component I have created. The component is fairly complicated, due to the specifics of the implementation, but I can easily render it iff I avoid using JSX syntax. However, if I use JSX, I cannot render the component at all and I get the following error:
TypeError: _this2.props.children.forEach is not a function
My code can be seen below (I also get a few warnings that I haven't gotten around to fixing yet, so you can just ignore those for the time being). Bear in mind that the structure of the HTML for the component is very strict (due to the CSS framework I'm using) and cannot be changed. Is there a way to use JSX for achieving the same result and, if so, what is it that I'm doing wrong?
// This function was based on this answer: https://stackoverflow.com/a/10734934/1650200
function generateUniqueId() {
// always start with a letter (for DOM friendlyness)
var idstr = String.fromCharCode(Math.floor((Math.random() * 25) + 65));
do {
// between numbers and characters (48 is 0 and 90 is Z (42-48 = 90)
var ascicode = Math.floor((Math.random() * 42) + 48);
if (ascicode < 58 || ascicode > 64) {
// exclude all chars between : (58) and # (64)
idstr += String.fromCharCode(ascicode);
}
} while (idstr.length < 32);
return (idstr);
}
// Technically this is not exactly a component, but I use it as such to make things simpler.
class Tab extends React.Component {
render() {
return React.createElement('div', {}, this.props.children);
}
}
// This is my Tabs component
class Tabs extends React.Component {
// In the constructor, I take all children passed to the component
// and push them to state with the necessary changes made to them.
constructor(props) {
super(props);
var state = {
group: 'tab_group_' + generateUniqueId(),
children: []
}
this.props.children.forEach(
function(child) {
if (!child instanceof Tab) {
throw "All children of a 'Tabs' component need to be of type 'Tab'. Expected type: 'Tab' Found Type: '" + child.class + "'";
return;
}
var tab = Object.assign({}, child);
tab.internalId = 'tab_' + generateUniqueId();
state.children.push(tab);
}
);
this.state = state;
}
// When rendering, I don't render the children as needed, but I create
// the structure I need to use for the final result.
render() {
var childrenToRender = [];
var groupName = this.state.group;
this.state.children.forEach(function(tab) {
childrenToRender.push(
React.createElement(
'input', {
type: 'radio',
name: groupName,
id: tab.internalId,
checked: true,
'aria-hidden': 'true'
}
)
);
childrenToRender.push(
React.createElement(
'label', {
'htmlFor': tab.internalId,
'aria-hidden': 'true'
},
'demo-tab'
)
);
childrenToRender.push(React.createElement('div', {}, tab.props.children));
});
return React.createElement('div', {
'className': 'tabs'
}, childrenToRender);
}
}
// This works fine
ReactDOM.render(
React.createElement(Tabs, {}, [React.createElement(Tab, {}, 'Hello world')]),
document.getElementById('root')
);
// This fails with the error mentioned above
// ReactDOM.render(
// <Tabs>
// <Tab>Hello, world!</Tab>
// </Tabs>,
// document.getElementById('root')
// );
<link rel="stylesheet" href="https://gitcdn.link/repo/Chalarangelo/mini.css/master/dist/mini-default.min.css">
<script src="https://unpkg.com/react#latest/dist/react.js"></script>
<script src="https://unpkg.com/react-dom#latest/dist/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone#6.15.0/babel.min.js"></script>
<div id="root"></div>
Update: This only happens if I actually pass only one <Tab> to the <Tabs> due to the way it's processed. If, for example, I use the following code, I can use JSX to render the component and its contents:
ReactDOM.render(
<Tabs>
<Tab>Hello, world!</Tab>
<Tab>Hello, world!</Tab>
</Tabs>,
document.getElementById('root')
);
After checking out what babel output from the JSX code, I realized that it was not ouputting something like [React.createElement(Tab, {}, 'Hello world')] but rather something more like React.createElement(Tab, {}, 'Hello world'), meaning it was not an array, thus causing problems with .forEach().
To anyone interested, what I did was check if this.props.children is an array and, if not, to actually turn it into one. Sample below:
if (!Array.isArray(this.props.children))
var tempProps = [this.props.children];
else
var tempProps = this.props.children;
tempProps.forEach(
// Rest of the code is pretty much the same as before
);
This is not a very elegant solution, so feel free to post more elegant answers if you know any.