Can't access React js component's passed down value - javascript

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

Related

Use const from another file in Reactjs

I have an object:
import React, {Component} from 'react';
import ProgressBar from "./ProgressBar";
class Languages extends Component {
state = {
languages: [
{id: 1, value: "XXX", xp: 1.5},
{id: 2, value: "CCC", xp: 1},
{id: 3, value: "AAA", xp: 2}
]
}
render() {
let {languages} = this.state;
const levels = ['Test', 'Bad', 'Sorry']
return (
<div className="languages">
<ProgressBar
programming={languages}
className="languagesDisplay"
levels={levels}
title="Languages"
/>
</div>
);
}
}
export default Languages;
import React from 'react';
const ProgressBar = (props) => {
return (
<div className={props.className}>
<h3>{props.title}</h3>
<div className="years">
<span>Experiences</span>
props.levels.map((level) => {
<span>level</span>
})
</div>
<span>level</span> return props.levels.map((level) =>level)
how can i display the const ['Test', 'Bad', 'Sorry'] from Languages.js in a <span> in a different React file?
Edit after seeing your response above: If the issue is just that the above code isn't working, here are a couple of things to check.
Inside of ProgressBar you've got a couple of errors in your JSX. First, you need curly braces around your JavaScript interpolation and secondly, you're not returning anything in your .map() function. If you were using parentheses it would be an implicit return, but with the curly braces you need a return statement. Try this instead:
import React from 'react';
const ProgressBar = (props) => {
return ( <div className={props.className}>
<h3> {props.title} </h3>
<div className ="years">
<span> Experiences </span>
{props.levels.map((level) => {
return (<span>{level}</span>)
})
} </div>
)};
My initial answer, which still may be helpful for understanding what's going on:
It's not entirely clear what you want to do, but here are a couple of things that might be helpful.
What's happening in your code above is that the levels variable, which is an array of strings, is being passed down from the parent component Languages into the child component ProgressBar via the props object.
When ProgressBar is called inside of Languages, it's properties (or props) are set (programming, className, levels, title).
The levels={levels} part means that the prop levels on ProgressBar is being set to the variable levels (the array of strings).
Inside of ProgressBar all of those properties are accessible in the props object that's passed as an argument. That's why you're able to access that array of strings with props.levels.map() which will map the array of strings however you tell it to (in this case by printing each individual item within a <span> tag).
So, with that understanding of what's happening here, here are a couple of things you could do to access the levels variable elsewhere in another file.
If levels is a constant that you want to access in multiple places, you could move it outside of the body of your Languages component and export it to use it in other places.
That could look like:
import React, {
Component
} from 'react';
import ProgressBar from "./ProgressBar";
export const levels = ['Test', 'Bad', 'Sorry']
class Languages extends Component {
state = {
languages: [{
id: 1,
value: "XXX",
xp: 1.5
},
{
id: 2,
value: "CCC",
xp: 1
},
{
id: 3,
value: "AAA",
xp: 2
}
]
}
render() {
let {
languages
} = this.state;
return ( <
div className = "languages" >
<
ProgressBar programming = {
languages
}
className = "languagesDisplay"
levels = {
levels
}
title = "Languages" /
>
<
/div>
);
}
}
export default Languages;
By exporting it from the top level, you could import it in another file exactly as it is.
import { levels } from '/insert-first-file-location-here'
Another option is to pass the levels variable into another component as a prop. This way if levels gets changed at the top level, those changes will drill down into subsequent components.
import React, {Component} from 'react';
import ProgressBar from "./ProgressBar";
class Languages extends Component {
state = {
languages: [
{id: 1, value: "XXX", xp: 1.5},
{id: 2, value: "CCC", xp: 1},
{id: 3, value: "AAA", xp: 2}
]
}
render() {
let {languages} = this.state;
const levels = ['Test', 'Bad', 'Sorry']
return (
<>
<div className="languages">
<ProgressBar
programming={languages}
className="languagesDisplay"
levels={levels}
title="Languages"
/>
</div>
<AnotherComponentThatUsesLevels
levels={levels} />
</>
);
}
}
export default Languages;
And then
import React from 'react'
export const AnotherComponentThatUsesLevels (props) => {
return (
<>
{/* do something with levels here, maybe map them like before*/}
{props.levels.map((level) => (<span>{level}</span>)}
</>
)
}
Does that help understand what's happening in the example and give you a couple of ways you could use that variable in another location?
You need to export that certain constant from your file like that:
import React, {
Component
} from 'react';
import ProgressBar from "./ProgressBar";
export const levels = ['Test', 'Bad', 'Sorry']
class Languages extends Component {
state = {
languages: [{
id: 1,
value: "XXX",
xp: 1.5
},
{
id: 2,
value: "CCC",
xp: 1
},
{
id: 3,
value: "AAA",
xp: 2
}
]
}
render() {
let {
languages
} = this.state;
return (
<div className="languages">
<ProgressBar
programming={languages}
className="languagesDisplay"
levels={levels}
title="Languages"
/>
</div>
);
}
}
export default Languages;
After it, you need to import it in the file where you want to access it:
import {levels} from '/path/to/file';

Setting up tabs on state

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}

Getting a Render not Function Error, when I run this Code Context API and Reactjs

Thanks for taking the time to read this. I have been at this now for a few hours and nearly got it right except now, Im Getting a "TypeError: render is not a function" Error and Can not figure it out, using Context API and Reactjs Please help
I have changed around States and props and back again this is the closest I got it to work
this is my parent file where I pass the UserProvider
import React, { Component } from "react";
import Group from "./Groups";
import JsonData from "../data/export";
import { UserProvider } from "./context/UserContext";
class GroupGrid extends Component {
render() {
// console.log(JsonData);
return (
<UserProvider value={JsonData}>
<div className='cards'>
<Group />
</div>
</UserProvider>
);
}
}
export default GroupGrid;
this is the child file
import React, { Component } from "react";
import UserContext from "../components/context/UserContext";
import { UserConsumer } from "../components/context/UserContext";
class GroupDetails extends Component {
static contextType = UserContext;
componentDidMount() {
const data = this.context;
// console.log(data); // { name: 'Tania', loggedIn: true }
}
render() {
return (
<UserConsumer>
{this.context.TransportGrid.GROUPS.map((value, index) => (
<div key={value.GROUP_ID} className='GroupDetail'>
<div className='groupRow1'>
<span className='Date_label'>Date:</span>
<span className='GroupDate'>
{value.GROUP_DATE}
</span>
<span className='Group_label'>Group No:</span>
<span className='GroupID'>{value.GROUP_ID}</span>
</div>
<div className='groupRow2'>
<span className='Driver_label'>Driver:</span>
<span className='DriverName'>
{value.DRIVER_NAME}
</span>
<span className='Reg_label'>Artic:</span>
<span className='VehcileReg'>
{value.VEHICLE_REG}
</span>
</div>
</div>
))}
</UserConsumer>
);
}
}
export default GroupDetails;
and this an example of the JSON it looking at
{
"TransportGrid": {
"GROUPS": [
{
"GROUP_ID": "1234",
"GROUP_DATE": "20/08/2019",
"DRIVER_ID": "22",
"DRIVER_NAME": "JIMMY BLOGGS",
"VEHICLE_REG": "XSRFDFDDF",
"START_COUNTRY": "COUNTRY1",
"END_COUNTRY": "COUNRTY2",
"MOVEMENTS": [
{
this is repeated like 180 times ANyone got any idea's?
Thanks in Advance
Problem is that your consumer from context API needs to just have a single children element as a function whereas you are having an array of JSX elements as children.
Also since you are using the latest context API you don't need to use the Consumer component, you could simply write your code as
class GroupDetails extends Component {
static contextType = UserContext;
componentDidMount() {
const data = this.context;
// console.log(data); // { name: 'Tania', loggedIn: true }
}
render() {
return (
<React.Fragment>
{this.context.TransportGrid.GROUPS.map((value, index) => (
<div key={value.GROUP_ID} className='GroupDetail'>
<div className='groupRow1'>
<span className='Date_label'>Date:</span>
<span className='GroupDate'>
{value.GROUP_DATE}
</span>
<span className='Group_label'>Group No:</span>
<span className='GroupID'>{value.GROUP_ID}</span>
</div>
<div className='groupRow2'>
<span className='Driver_label'>Driver:</span>
<span className='DriverName'>
{value.DRIVER_NAME}
</span>
<span className='Reg_label'>Artic:</span>
<span className='VehcileReg'>
{value.VEHICLE_REG}
</span>
</div>
</div>
))}
</React.Fragment>
);
}
}
export default GroupDetails;

Vue.js - Dynamic component import in data and computed properties

I have component 'Page' that should display a component which is retrieved via its props.
I managed to get my component loads when I harcode my component path in my component data like this :
<template>
<div>
<div v-if="includeHeader">
<header>
<fv-header/>
</header>
</div>
<component :is="this.componentDisplayed" />
<div v-if="includeFooter">
<footer>
<fv-complete-footer/>
</footer>
</div>
</div>
</template>
<script>
import Header from '#/components/Header/Header';
import CompleteFooter from '#/components/CompleteFooter/CompleteFooter';
export default {
name: 'Page',
props: {
componentPath: String,
includeHeader: Boolean,
includeFooter: Boolean
},
data() {
componentDisplayed: function () {
const path = '#/components/my_component';
return import(path);
},
},
components: {
'fv-header': Header,
'fv-complete-footer': CompleteFooter,
},
}
</script>
But with the data I cannot refer to my props within my function as this is undefined.
I tried to used computed properties instead of data but I have the error "src lazy?0309:5 Uncaught (in promise) Error: Cannot find module '#/components/my_component'. But the module exists! But maybe not at that time ?
computed: {
componentDisplayed: function () {
const path = `#/components/${this.componentPath}`;
return import(path);
},
},
There must be away to deal with that but I am quite a beginner to vue.js :)
Instead of trying to import the component in your child component, instead import it in the parent component and pass the entire component as a prop.
<template>
<div :is="component" />
</template>
<script>
export default {
name: "page",
props: {
component: {
required: true
}
}
};
</script>
And in the parent
<page :component="component" />
and
import Page from './components/Page';
// and further down
data () {
return {
component: HelloWorld
}
}

How to render an object from an array into another component in React?

From an array of posts that are passed and rendered to one component, I want to be able to render a single post of this array into another component but I can't find a way to do this.
I have two components that I use for this case, the first component "Blog" renders a preview of all the posts that are in the array. Each post has a<Link to={/blog/post-1/:${post.id}}>Go to post</Link> to the second component "Post" which renders a single post from the array. I am using react boiler plate for this.
First my container who has a dummy array of posts:
import React from 'react';
// other imported stuff
import Blog from 'components/Blog';
class BlogPage extends React.Component {
render() {
// dummy posts data
const posts = [
{
id: 1,
title: 'How to Cook Blue Meth',
description: 'Lorem ipsum dolor sit amet, turpis at',
thump: 'thump.jpg',
hero: '/img/',
category: 'k1',
fullname: 'Walter White',
published: '10.05.2016, 15:30pm',
},
{
id: 2,
title: 'Passenger',
description: 'Lorem ipsum dolor sit amet, turpis at',
thump: 'thump.jpg',
hero: '/img/',
category: 'k2',
fullname: 'Chino Moreno',
published: '10.05.2016, 15:30pm',
},
// and more posts...
];
return (
// this is the first component
<div>
<Blog posts={posts} />
</div>
);
}
}
export default connect(null, mapDispatchToProps)(BlogPage);
Here is the first component Blog:
import React from 'react';
import { Link } from 'react-router';
class Blog extends React.Component {
renderPosts() {
return (
<ul>
{this.props.posts.map((post, idx) => {
return (
<li key={idx}>
<p>{post.title}</p>
<p>{post.category}</p>
<p>{post.thump}</p>
<p>{post.fullname}</p>
<p>{post.published}</p>
<Link to={`/blog/post-1/:${post.id}`}>Go to post </Link>
</li>
);
})}
</ul>
);
}
render() {
return (
<div>
{this.renderPosts()}
</div>
);
}
}
Blog.propTypes = {
props: React.PropTypes.array,
};
export default Blog;
And the second component Post:
import React from 'react';
class Post extends React.Component {
render() {
return (
<div>
<p>{this.props.post.hero}</p>
<p>Title:{this.props.post.title}</p>
<p>{this.props.post.description}</p>
<p>Category:{this.props.post.category}</p>
<p>{this.props.post.thump}</p>
<p>Author:{this.props.post.fullname}</p>
<p>Published:{this.props.post.published}</p>
</div>
);
}
}
Post.propTypes = {
post: React.PropTypes.object,
};
export default Post;
I import this second component into another container:
import React from 'react';
import Post from 'components/Blog/Post';
class PostPage extends React.Component {
render() {
return (
<div>
<Post post={post} />
</div>
);
}
}
export default connect(null, mapDispatchToProps)(PostPage);
This are my routes:
{
path: '/blog',
name: 'blog',
getComponent(nextState, cb) {
System.import('containers/BlogPage')
.then(loadModule(cb))
.catch(errorLoading);
},
},
{
path: '/blog/post-1/:id',
name: 'blog-post-1',
getComponent(nextState, cb) {
System.import('containers/BlogPage/PostPage')
.then(loadModule(cb))
.catch(errorLoading);
},
},
I just added this routes to the routes.js in the react boiler plate.
In this point I don't know how to pass the single post to get rendered. Any help would be appreciated
First you need to define the data in the reducer, that way you will be able to send it to any page that you want.
In this case I would recommend you to create two folders inside the containers folder, one for the lists of post and one for the single post.
You will need to define a reducer to store the list of posts (instead of defining the list in the component itself), take a look at the code already in the boiler plate: https://github.com/mxstbr/react-boilerplate/blob/master/app/containers/HomePage/reducer.js
Then you need to connect the reducer with the component and map the redux state with the component props, like this: https://github.com/mxstbr/react-boilerplate/blob/master/app/containers/HomePage/index.js#L139
Finally you would use those props to render the list, basically using this.props.posts on your BlogPage component, something similar to this: https://github.com/mxstbr/react-boilerplate/blob/master/app/containers/HomePage/index.js#L76
Once you have the list renderer you will need to create the PostPage component in a different folder, then connect the reducer that contains the data and get the item from the ID you are receiving in the URL param, (usually instead of that you would request to the server the data, but for the sake of simplicity just get the post from the existing reducer).
The idea here is to use redux to manage the data, that way you will be able to send data to any component, using the connect and mapping the state to the props.
PS: Don't forget to inject your reducer when defining the route: https://github.com/mxstbr/react-boilerplate/blob/master/app/routes.js#L33 this is a very important step ;)

Categories