Can i use the same component inside component in react? - javascript

import React from 'react';
class Feladatlista extends React.Component{
constructor(props){
super(props);
}
feladatok = () => {
if(this.props.fl.length){
this.props.fl.map(fl => {
return <Feladatlista tipus={fl.tipus} nev={fl.nev} rang={fl.rang} fl={fl.fl}/>
})
}
}
render(){
return(
<div>
<div className={this.props.tipus}>
<p>{this.props.nev}</p>
<p>{this.props.rang}</p>
</div>
<div className='gyerek'>
{this.feladatok}
</div>
</div>
)
}
}
export default Feladatlista;
Here is my code. My plan is, to have a database with nested objects, where i push the data with the same components connected with each other. Like this:
const feladat = [
{név: 'asd',
tipus: 'a',
rang: '1',
fl:[
{név: 'dd',
tipus: 'a',
rang: '1',
fl: []},
{név: 'eded',
tipus: 'a',
rang: '2',
fl: [
{név: 'das',
tipus: 'a',
rang: '1',
fl: []},
{név: 'dasd',
tipus: 'a',
rang: '2',
fl: [
{név: 'dasd',
tipus: 'a',
rang: '1',
fl: []
}]
}]
}]
}
]
In this way, in the main (App.js) i define the first element, and it loops through all of the array. But i get the error message: index.js:2178 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.. The problem is that i want to use the same component in the component, or other?

First, you need to return the data from feladatok,
Second, you need to call the function from render like this.feladatok()
class Feladatlista extends React.Component {
feladatok = () => {
if (this.props.fl.length) {
return this.props.fl.map((fl, index) => {
return (
<Feladatlista
key={index}
tipus={fl.tipus}
nev={fl.nev}
rang={fl.rang}
fl={fl.fl}
/>
);
});
}
return null;
};
render() {
console.log(this.props.fl);
return (
<div>
<div className={this.props.tipus}>
<p>{this.props.nev}</p>
<p>{this.props.rang}</p>
</div>
<div className="gyerek">{this.feladatok()}</div>
</div>
);
}
}
Working demo

Related

Working with state on recursive components

I'm writing a component that renders itself inside recursively and is data-driven
Attaching my sandbox snippet, as it will be easier to see there.
This is my data:
var builderStructureData = [
{
id: 123,
value: 3,
children: []
},
{
id: 345,
value: 5,
children: [
{
id: 4123,
value: 34,
children: [
{
id: 342342,
value: 33,
children: []
}
]
},
{
id: 340235,
value: 3431,
children: [
{
id: 342231342,
value: 3415,
children: []
}
]
}
]
}
];
and it renders like this:
This is my App.js:
import { useState } from "react";
import "./App.css";
import Group from "./components/group";
import builderStructureData from "./components/builderStructureData";
function App() {
const [builderStructure, setBuilderStructure] = useState(
builderStructureData
);
return (
<div className="App">
{builderStructure.map((x) => {
return <Group key={x.id} children={x.children} value={x.value} />;
})}
</div>
);
}
export default App;
And this is my recursive component:
import React from "react";
export default function Group(props) {
let childrenArray = [];
if (props.children) {
props.children.map((x) => childrenArray.push(x));
}
return (
<div className="group" draggable>
<p>this is value: </p>
<input value={props.value} readOnly={true}></input>
<button>Add Group</button>
{childrenArray.map((x) => {
return <Group key={x.id} children={x.children} value={x.value} />;
})}
</div>
);
}
I can render the components based on the data, and it seems to be handling recursion fine. I need to store the state on the App.js page and be able to change it from within child components. For example, if I update the "value" field of the component with ID = 342342, I want it to update that corresponding object in the state no matter how deeply nested it is, but not sure how to do that as it is not as simple as just passing a prop.
Am I taking the right approach with my code snippet? How can I do the state update?
I would advise the state normalization approach - here is an example for redux state - https://redux.js.org/usage/structuring-reducers/normalizing-state-shape - but you can use this approach with your state. So - your state will look like this:
state = {
items: {
[123]: {
id: 123,
value: 3,
childrenIds: []
},
[345]: {
id: 345,
value: 5,
childrenIds: [4123, 340235]
},
[4123]: {
id: 4123,
value: 34,
parentId: 345,
childrenIds: [342342]
},
[342342]: {
id: 342342,
value: 33,
parentId: 4123,
childrenIds: []
},
[340235]: {
id: 340235,
value: 3431,
parentId: 345,
childrenIds: [342231342]
},
[342231342]: {
id: 342231342,
value: 3415,
parentId: 340235
childrenIds: []
}
}
}
Here the field "childrenIds" is an optional denormalization for ease of use, if you want - you can do without this field. With this approach, there will be no problem updating the state.
You are thinking this in a wrong way, it should be very easy to do what you want.
The most imported thing is to make a little small changes in Group
Please have a look
import React from "react";
export default function Group(props) {
const [item, setItem] = React.useState(props.item);
let childrenArray = [];
if (item.children) {
item.children.map((x) => childrenArray.push(x));
}
const updateValue = ()=> {
// this will update the value of the current object
// no matter how deep its recrusive is and the update will also happen in APP.js
// now you should also use datacontext in app.js togather with state if you want to
// trigger somethings in app.js
item.value =props.item.value= 15254525;
setState({...item}) // update the state now
}
return (
<div className="group" draggable>
<p>this is value: </p>
<input value={item.value} readOnly={true}></input>
<button>Add Group</button>
{childrenArray.map((x) => {
return <Group item={x} />;
})}
</div>
);
}
The code above should make you understand how easy it is to think about this as an object instead of keys.
Hop this should make it easy for you to understand

setting state within nested response

I am building a react app and I am setting the state with api of nested response of nested state But the state is not setting the way I want.
response that is receiving from api
[
{
"id": 70,
"title": "feefifef",
"images": [
{
"id": 28,
"text": "First Image"
"blog_id": 70,
},
{
"id": 28,
"text": "First Image",
"blog_id": 70,
}
]
}
]
App.js
class App extends React.Component {
constructor(props){
super(props)
this.state = {
blogs = [
{
id: 0,
title: "",
images: [
{
id:0,
text:""
}
]
}
]
}
}
componentDidMount() {
let data;
axios.get('http://127.0.0.1:8000/api/blogs/').then((res) => {
data = res.data;
this.setState({
blogs: data.map((blog) => {
return Object.assign({}, blog, {
id: blog.id,
title: blog.title,
images: blog.images,
}
})
})
})
}
render() {
const blogs = this.state.blogs.map((blog) => (
<BlogList
id={blog.id}
title={blog.title}
images={blog.images}
/>
))
}
return (
<div>{blogs}</div>
)
}
class BlogList extends React.Component {
constructor(props){
super(props)
}
return (
<div>
Title: {this.props.title}
Images: {this.props.images}
</div>
)
}
What is the problem ?
Images are not showing after Title. I am trying to show all images in BlogList class of every blog.
I have also tried using (in BlogList class)
this.props.images.map((img) => {
return (
<div>
Title: {this.props.title}
Images: {img.text}
</div>
)
}
But it showed me
this.props.images.map is not a function.
then I think the problem is with setting state of images (I may be wrong).
When I tried to print this.props.images then it is showing
0: {id: 28, text: '1111', blog_id: 71}
length: 1
[[Prototype]]: Array(0)
I am new in react, Any help would be much Appreciated. Thank You in Advance
this.props.images is an array and hence you can't use {this.props.images} directly. Other wise you will get an error like this "Objects are not valid as a React child. If you meant to render a collection of children, use an array instead"
You have to use something like this
render() {
return (
<div>
Title: {this.props.title} <br/>
Images:
{this.props.images?.map((image, i) => (
<div key={image.id}>
{image.id}<br/>
{image.text}<br/>
{image.blog_id} <br/>
</div>
))}
</div>
);
}

How do I pass different values depending on the imported data in React?

I want to take data from js files classified as categories such as 'Delivery' and 'Cafe' and deliver different data to different pages.
I thought about how to import it using map(), but I keep getting errors such as 'products' is not defined.'
It must be done, but it is not implemented well with javascript and react weak. If you know how to do it, I'd appreciate it if you could let me know.
Products.js
export const Product = [
{
Delivery: [
{
id: '101',
productName: '허니랩',
summary: '밀랍으로 만든 친환경 식품포장랩 허니랩.',
description:
'~~',
images: ['3k7sH9F'],
companyName: '허니랩',
contact: '02-6082-2720',
email: 'lesslabs#naver.com',
url: 'https://honeywrap.co.kr/',
},
{
id: '102',
productName: '허니포켓',
summary: '밀랍으로 만든 친환경 식품포장랩 허니랩. 주머니형태.',
description:
"~~",
images: ['4zJEqwN'],
companyName: '허니랩',
contact: "02-6082-2720",
email: "lesslabs#naver.com",
url: "https://honeywrap.co.kr/",
},
],
},
{
HouseholdGoods: [
{
id: '201',
productName: '순둥이',
summary: '아기용 친환경 순한 물티슈',
description:
'~',
images: ['4QXJJaz'],
companyName: '수오미',
contact: '080-000-3706',
email: 'help#sumomi.co.kr',
url: 'https://www.suomi.co.kr/main/index.php',
},
{
id: '202',
category: ['HouseholdGoods'],
productName: '순둥이 데일리',
summary: '친환경 순한 물티슈',
description: '품질은 그대로이나 가격을 낮춘 경제적인 생활 물티슈',
images: ['OMplkd2'],
companyName: '수오미',
contact: '080-000-3706',
email: 'help#sumomi.co.kr',
url: 'https://www.suomi.co.kr/main/index.php',
},
],
},
];
Delivery.js
(The file was named temporarily because I did not know how to classify and deliver data without creating a js file separately.)
import React from "react";
function Delivery(
productName,
companyName,
contact,
email,
url,
summary,
description
) {
return (
<div className="Product">
<div className="Product__data">
<h3 className="Product__name">{productName}</h3>
<h4>{companyName}</h4>
<h5>Contact: {contact}</h5>
<h5>Email: {email}</h5>
<h5>URL: {url}</h5>
<p className="Product__summary">{summary}</p>
<p className="Proudct__descriptions">{description}</p>
</div>
</div>
);
}
export default Delivery;
Category.js
import React from "react";
import Delivery from "./Delivery";
import { Product } from "./Products";
class Category extends React.Component {
render() {
state = {
products: [],
};
this.setState(_renderProduct());
return <div>{products ? this._renderProduct() : "nothing"}</div>;
}
_renderProduct = () => {
const { products } = this.state;
const renderProducts = products.map((product, id) => {
return (
<Delivery
productName={Product.productName}
companyName={Product.companyName}
contact={Product.contact}
email={Product.email}
url={Product.url}
summary={Product.summary}
description={Product.description}
/>
);
});
};
}
export default Category;
Sorry and thank you for the long question.
There are quite a few different problems I've found.
First is that you call setState inside render in the Category component, this causes an infinite loop. Instead call setState inside a lifecycle method like componentDidMount or use the useEffect hook if using functional components.
Another problem is that state in Category is also defined inside render. In class components you would normally put this in a class constructor outside of render.
In your setState call you refer to _renderProduct(), this should be this._renderProduct() instead.
Now the main problem here is the structure of your data / how you render this structure.
Products is an array of objects where each object either has a Delivery or HouseholdGoods property which is an array of products. I would advise you to change this structure to something more like this:
export const Product = {
Delivery: [
{
id: "101",
},
{
id: "102",
},
],
HouseholdGoods: [
{
id: "201",
},
{
id: "202",
},
],
};
or this:
export const Product = [
{ id: "101", productType: "Delivery" },
{ id: "102", productType: "Delivery" },
{ id: "201", productType: "HouseholdGoods" },
{ id: "202", productType: "HouseholdGoods" },
];
I personally prefer the second structure, but I've implemented the first as this seems to be what you were going for:
class Category extends React.Component {
constructor(props) {
super(props);
this.state = {
products: null,
};
}
componentDidMount() {
this.setState({ products: Product });
}
render() {
const { products } = this.state;
return (
<div>
{products
? Object.keys(products).map((productKey) => {
return (
<div key={productKey}>
{products[productKey].map((product) => {
return (
<Delivery
key={product.id}
productName={product.productName}
companyName={product.companyName}
contact={product.contact}
email={product.email}
url={product.url}
summary={product.summary}
description={product.description}
/>
);
})}
</div>
);
})
: "no products"}
</div>
);
}
}
We need a nested loop here, because we need to map over each property key and over the array of objects inside each property. If you use the other structure for Product I've shown, you can simply map over Product without needing two loops.
Now the last important problem was that you weren't destructuring the props inside your Delivery component, instead you should do something like this:
function Delivery({
productName,
companyName,
contact,
email,
url,
summary,
description,
}) {
return (
<div className="Product">
<div className="Product__data">
<h3 className="Product__name">{productName}</h3>
<h4>{companyName}</h4>
<h5>Contact: {contact}</h5>
<h5>Email: {email}</h5>
<h5>URL: {url}</h5>
<p className="Product__summary">{summary}</p>
<p className="Proudct__descriptions">{description}</p>
</div>
</div>
);
}
Example Sandbox

Why can't I declare a function before render in React?

So my code works, but if I move handleClick() to the render, It will throw an error. Same if I try to declare a function like
var handleClick = () => {
this.setState({reservationVisible: true})
console.log(this.state.reservationVisible)}
outside render.
Also when I'm passing handleClick() as a prop, I need to call {this.handleClick.bind(this)} and when I'm using a function, declared inside render, {handleClick.bind(this) is enough. I don't really understand why. Where should I declare functions then? Outside or inside render? Should I use functions or methods?
Here is my code:
import React, { Component } from 'react';
import Room from './Room'
import Form from './Form'
class Rooms extends Component {
constructor(props){
super(props);
this.state = {reservationVisible: false}
}
handleClick(e){
this.setState({reservationVisible: true})
console.log(this.state.reservationVisible)
}
render(){
let rooms = [
{
roomNumber: '1',
type: 'Cool room',
price: '130 $',
goods: ['radio', 'phone']
},
{
roomNumber: '2',
type: 'Cozy Room ',
price: '165 $',
goods: ['radio', 'phone, tv']
},
{
roomNumber: '3',
type: 'Dirty Room',
price: '130 $',
goods: ['balcony', 'phone']
},
{
roomNumber: '4',
type: 'Like Real Dirty Room',
price: '90 $',
goods: ['fridge', 'phone', 'balcony']
}
]
let getElements = (room, i) => {
return(
<Room
key={i}
roomNumber={room.roomNumber}
type={room.type}
price={room.price}
goods={room.goods.map(good => good + ", ")}
onClick={this.handleClick.bind(this)}
/>
)
};
let roomsMapped = rooms.map(getElements);
return(
<div>
{roomsMapped}
</div>
)
}
}
export default Rooms
and the Room component
import React, { Component } from 'react';
class Room extends Component{
render(){
return (
<div className="room">
<div className="image"><h1>Image nr {this.props.roomNumber}</h1></div>
<div className="buttonGroup">
<div className="button galleryButton">Gallery</div>
<div className="button reserve" onClick={this.props.onClick.bind(this)}> I'll take it</div>
</div>
<div className="info">
<div className="topInfo">
<span className="left">{this.props.type}</span>
<span className="right">{this.props.price}</span>
</div>
<div className="additional">
{this.props.goods}
</div>
</div>
</div>
)
}
}
export default Room

React - Tree Component

I am trying to make a component in React to recursively display the names in a data tree. I am not that familiar with React and am not sure what I can do in my code to remove the error I get in the console.
The error is Uncaught SyntaxError: embedded: Adjacent JSX elements must be wrapped in an enclosing tag
Here is a jsFiddle to my code: https://jsfiddle.net/go79b0dp/
Here is my example code:
var treeObj = [
{
id: 1,
name: 'Bob',
children: [
{
id: 2,
name: 'Mary',
children: [
{id: 4, name: 'Suzy'}
]
},
{
id: 3,
name: 'Phil',
children: [
{id: 5, name: 'Jon'},
{id: 6, name: 'Paul'}
]
}
]
}
];
var TreeView = React.createClass({
getInitialState: function() {
return {
people: treeObj
};
},
render: function() {
var people = this.state.people;
var nodes = people.map((i) => <TreeNode node={i} children= {i.children} />)
return (
<ul>{nodes}</ul>
);
}
});
var TreeNode = React.createClass({
render: function() {
var nodes;
if (this.props.children) {
nodes = this.props.children.map((i) => <TreeNode node={i} children={i.children} />);
}
return (
<li>{this.props.node.name}</li>
<ul>{nodes}</ul>
);
}
});
ReactDOM.render(<TreeView />, document.getElementById('container'));
Your TreeNode component returns two sibling components: <li> and <ul>. Basically, you're trying to return two things from the render function, and you can't do that.
Normally, the recommended solution is to wrap them both in another element. For example:
return (<div>
<li>{this.props.node.name}</li>
<ul>{nodes}</ul>
</div>);
However, for the tree structure you're trying to create, it would probably be better to put the <ul> inside the <li>. That would be:
return (<li>
{this.props.node.name}
<ul>{nodes}</ul>
</li>);
This is how nested lists are commonly done in HTML.

Categories

Resources