I'm trying to setup the tabs a React component in the parent component states, something like this
import React from 'react';
import Component1 from '../myChildComponents/Component1';
import Component2 from '../myChildComponents/Component2';
import Component3 from '../myChildComponents/Component3';
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
tabs: [
{id: '1', text: 'Tab 1', component: Component1},
{id: '2', text: 'Tab 2', component: Component2},
{id: '3', text: 'Tab 3', component: Component3},
]
}
}
render() {
return (
<!-- All the other stuff goes here, like the tabs headers -->
<TabContent>
{
this.state.tabs.map((t, i) =>
<TabPane key={i} tabId={t.tabId}>
<t.component {...this.props.data}>
</TabPane>
)
}
</TabContent>
)
}
}
Can something like this be achieved? I already tried using the React.createComponent function, but this worked
Edit1: Updated to reflect current test implementation, still seeing the following message on the console
Uncaught (in promise) Invariant Violation: 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. Check the render metho
Yeah you can use a component like that.
render() {
return (
<!-- All the other stuff goes here, like the tabs headers -->
<TabContent>
{
this.state.tabs.map((t, i) =>
<TabPane key={i} tabId={t.tabId}>
<t.component {...t.data}/>
</TabPane>
)
}
</TabContent>
)
}
Only thing you need to change is:
your object key is component; lower case
you need to set the props by using the spread operator on the t.data object: {...t.data}
Related
I keep getting this weird error in my React that says
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.
Check the render method of `ContactTemplate`.
I tried to remove each of the import to see where the error is, but nothing works.
My ContactTemplate.jsx:
import React from 'react';
import { Container } from '~/components/interface/Container';
import PreviewBar from '~/components/PreviewBar';
import HeroFull from '~/components/HeroFull/HeroFull';
import { Wrapper, Columns, Paragraph, BigText } from './ContactTemplate.styles';
import { Link } from '~/components/interface/Link';
const ContactTemplate = ({ preview }) => {
const data = [
{
name: 'Name 1',
job: 'Bestuursrechts',
phone: '+31 (0) 612345678',
email: 'Email',
link: 'https://www.linkedin.com',
},
{
name: 'Name 2',
job: 'Intellectuele eigendom en contractenrecht',
phone: '+31 (0) 612345678',
email: 'email',
link: 'https://www.linkedin.com',
},
];
return (
<>
<Wrapper>
{preview && <PreviewBar />}
<HeroFull
title="Contact"
intro="We offer ...."
/>
</Wrapper>
<Container>
<Columns>
{data.map(item => (
<div>
<BigText>{item.name}</BigText>
<Paragraph>{item.job}</Paragraph>
<Paragraph>{item.phone}</Paragraph>
<Paragraph>{item.email}</Paragraph>
<Link>{item.link}</Link>
</div>
))}
</Columns>
</Container>
</>
);
};
export default ContactTemplate;
Could someone help me out with this please?
If there are more files needed I'll add them on request.
Most likely you're trying to import { ContactTemplate } from "./ContactTemplate", but you're using export default. At this point you should import ContactTemplate from "./ContactTemplate"
Can you confirm if this is the case?
Can you show the component, where you import and trying to use ContactTemplate?
I solved it myself. The first problem was that my Docker was stuck so I had to restart it. After I restarted it I tried to remove each import individually to see where the problem was and it was the { Link } that needed to be just Link. Thanks everyone else for helping!
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'm fairly new to react and i would like to know why i can't access my props that are passed down.
In my StatContentBet.js Component, i cannot access the props object values which i passed down from StatContent.js.
I can access this.props.img, but not this.props.bet.img, even though this.props.bet is a valid object.
https://gyazo.com/52347142134362b9cc4b7112c18ceaaf
Here is my StatContentBet.js (Where i'm trying to call the passed down from)
import React from "react";
import MiniDice from "./MiniDice";
class StatsContentBet extends React.Component {
render() {
return (
<div className="statsConentBet">
<div className="betInfo">
<img
className="betInfo-userImg"
src={this.props.img}
/>
<span className="betInfo-username">Richard Henricks</span>
<div className="betInfo-dices">
{this.props.betChoices.map((betChoice, index) => {
console.log(betChoice)
})}
</div>
</div>
</div>
);
}
}
export default StatsContentBet;
StatContent.js (Where i'm calling the
import React, { Component } from "react";
import StatContentBet from "./StatsContentBet";
class StatContent extends Component {
constructor() {
super();
this.state = {
};
}
render() {
let bets = [{
id:1,
username:"test",
img: "https://miro.medium.com/max/1200/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg",
diceChoices: [1,2,3,4,5,6,1]
},{
id:2,
username:"test",
img: "https://miro.medium.com/max/1200/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg",
diceChoices: [1,2,3,4,5,6,1]
},{
id:3,
username:"test",
img: "https://miro.medium.com/max/1200/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg",
diceChoices: [1,2,3,4,5,6,1]
},{
id:4,
username:"test",
img: "https://miro.medium.com/max/1200/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg",
diceChoices: [1,2,3,4,5,6,1]
}]
return (
<div id="statsContentContent">
{/* <StatContentBet img='https://miro.medium.com/max/1200/1*mk1-6aYaf_Bes1E3Imhc0A.jpeg' /> */}
{bets.map((bet, i) =>
<StatContentBet
key={i}
betChoices={bet.diceChoices}
bet={bet}
img={bet.img}
/>
)}
</div>
)
}
}
export default StatContent;
All the help is greatly appreciated!
It's working fine for me https://jsfiddle.net/hawk939393/19a7bgxL/4/; I'm not getting any errors related to undefined.
P.s. you just have a typo in a component name StatContentBet -> StatsContentBet
Edit: Make the following change inside your InputDices component:
StatsContentBet betChoices={[]}></StatsContentBet>
or you can check inside StatsContentBet whether this.props.betChoices is defined: if defined return jsx, else return something else return null
In the Parent component I have:
<todo-item v-for="(todo, index) in todos" :key="todo.id" :todo="todo" :index="index">
</todo-item>
which just iterates through todos array and gets each todo object and by using props passes each Object and its index to the child component. todo-item registered in Child component.
todos is an array of objects:
todos: [
{
'id': 1,
'title': 'Object 1'
},
{
'id': 2,
'title': 'Object 2'
}
]
Child component:
<template>
<div class="todo-item">
<div class="todo-item-left">
<div>{{ todo.title }}</div>
</div>
</div>
</template>>
<script>
export default {
name: 'todo-item',
props: {
todo: {
type: Object,
required: true
},
index: {
type: Number,
required: true
}
}
}
</script>
I don't know why it doesn't render each todo on the page, I have a blank page. Even though in Vue DevTools It shows that I have these objects.
Did I miss something?
EDIT:
There is an error, sorry the error flag were off hence didn't saw it.
Error message:
[Vue warn]: Unknown custom element: - did you register the component correctly? For recursive components, make sure to provide the "name" option.
As you can see above I did register the component in Child component.
And yes I did import the child component in Parent component by doing:
//Parent component
import ToDoItem from './ToDoItem'
export default {
name: 'todo-list',
components: {
ToDoItem,
},
You have problem with cases so you should import that component in parent one as follows :
import TodoItem from './TodoItem'
and register it like :
export default{
....
components:{
TodoItem
}
....
}
for more details check this
a common mistake
dont forget import child component in parent component
import ChildComponent fromt './ChildComponent';
export default{
components:{
ChildComponent
}
}
I have two modules that I want to share a const array. One of these modules includes both the const array and a component, whilst the other module only includes a component.
This is what I have in module "A".
export const ORDER_COLUMNS = [
{ name: 'orderNumber', title: 'Order', width: '10%', type: 'string' },
{ name: 'orderType', title: 'Type', width: '10%', type: 'string' }
];
class OrderGridControl extends React.Component {
constructor(props) {
super(props);
this.state = {
orderColumns: ORDER_COLUMNS
};
}
...
}
export default OrderGridControl;
And in module "B".
import {OrderGridControl, ORDER_COLUMNS} from 'component/order-grid-control';
class OrderQueryPage extends React.Component {
constructor(props) {
super(props);
this.state = {
orderColumns: ORDER_COLUMNS
};
console.info(this.state.orderColumns);
}
...
render() {
return (
<div>
<PropertyGrid gridSetup={this.state.orderColumns} />
</div>
);
}
}
When I run this I get the following error. invariant.js:39 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. Check the render method of 'moduleB'.
However, the console.info(this.state.orderColumns) line logs all the column objects I expect.
Interestingly, if I copy the array into module "B" and assign the columns in the constructor exactly the same way it seems to work. It only seems to be an issue when I'm importing from the other module.
You've got it almost right-- you're exporting a default export (OrderGridControl) and a named export (ORDER_COLUMNS).
However, in B.js, you're trying to import two named exports.
Modify your import to look like this:
import OrderGridControl, { ORDER_COLUMNS } from 'component/order-grid-control';
The advantage of having a default export is that you don't have to match its name exactly when importing it, so you could do something like
import GridControl, { ORDER_COLUMNS } from 'component/order-grid-control';