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

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

Related

React JS: How to add multiple placeholder object inside components

Sorry this question might be duplicated, but none of the existing answers helped me
I'm a beginner in React and js
I want to add multiple objects inside the component
Like:
src={url}
name={text}
subTitle={subtext}
my index.js
const tableColumns = [
{
title: 'Title/Artist',
dataIndex: 'name',
key: 'name',
render: (text) => (
<div className="d-flex align-items-center">
<AvatarStatus
shape="square"
src="https://i.scdn.co/image/ab67616d00001e02bd26ede1ae69327010d49946"
name={text}
subTitle="Dua Lipa"
/>
</div>
),
},
];
return (
<>
<Table
className="no-border-last"
columns={tableColumns}
dataSource={recentReleasesData}
rowKey='id'
pagination={false}
/>
</>
my data.js
export const RecentReleasesData = [
{
id: '#5332',
artwork: 'https://i.scdn.co/image/ab67616d00001e02bd26ede1ae69327010d49946',
name: 'Future Nostalgia',
artist: 'Dua Lipa',
label: 'Warner Records',
barcode: '19029500',
releasedate: '2021-02-11',
tracks: '11',
promolink: 'Smart Link',
status: 'Approved',
},
{
id: '#6438',
artwork: 'https://i.scdn.co/image/ab67616d00001e02caf82abb2338880577e472be',
name: 'Love',
artist: 'Someonw',
label: 'UMG Records',
barcode: '50029500',
releasedate: '2017-08-21',
tracks: '2',
promolink: 'Smart Link',
status: 'Rejected',
},
];
My comp AvatarStatus.js
import React from 'react';
import PropTypes from 'prop-types'
import { Avatar } from 'antd';
const renderAvatar = props => {
return <Avatar {...props} className={`ant-avatar-${props.type}`}>{props.text}
</Avatar>;
}
export const AvatarStatus = props => {
const { name, suffix, subTitle, id, type, src, icon, size, shape, gap, text,
onNameClick } = props
return (
<div className="avatar-status d-flex align-items-center">
{renderAvatar({icon, src, type, size, shape, gap, text })}
<div className="ml-2">
<div>
{
onNameClick ?
<div
onClick={() => onNameClick({name, subTitle, src, id})}
className="avatar-status-name clickable">{name}
</div>
:
<div className="avatar-status-name"><a href="javascript:void(0)">
{name}</a>
</div>
}
<span>{suffix}</span>
</div>
<div className="text-muted avatar-status-subtitle">{subTitle}</div>
</div>
</div>
)
}
AvatarStatus.propTypes = {
name: PropTypes.string,
src: PropTypes.string,
type: PropTypes.string,
onNameClick: PropTypes.func
}
export default AvatarStatus;
https://reactjs.org/docs/components-and-props.html
components are like JavaScript functions. They accept arbitrary inputs (called “props”) and return React elements describing what should appear on the screen.
This function is a valid React component because it accepts a single “props” (which stands for properties) object argument with data and returns a React element. We call such components “function components” because they are literally JavaScript functions.
codepen example
I found the solution
index.js
render: (_, record) => (
<Flex>
<AvatarStatus
shape="square"
size={50}
src={record.artwork}
name={record.title}
subTitle={record.artist}/>
</Flex>
),

React - dynamic background image

Im new to React.
Im building and app where one of my components need to have a dynamic background image.
i have the menu-item component where it gets 2 props one of them is imgName which hold the the name like shoes.jpg.
for some reason i cant get it to be the background image.
here some of the code i have wrote
main-menu component
import React from 'react';
import MenuItem from '../menu-item/menu-item.component'
import './main-menu.style.scss'
class MainMenu extends React.Component {
constructor() {
super()
this.state = {
sections: [{
title: 'pants',
imgName: 'pants.jpg',
id: 1
},
{
title: 'shirts',
imgName: 'shirts.jpg',
id: 2
},
{
title: 'hats',
imgName: 'hats.jpg',
id: 14
},
{
title: 'jackets',
imgName: 'jackets.jpg',
id: 12
},
{
title: 'shoes',
imgName: 'shoes.jpg',
id: 6
}
]
}
}
render() {
return (
<div className="main-menu">
{this.state.sections.map(({ title, id, imgName }) => {
return (
<MenuItem imgName={imgName} title={title} key={id} />
)
})}
</div>
)
}
}
export default MainMenu
menu-item component
import React from 'react';
import './menu-item.styles.scss'
const MenuItem = ({ title,imgName }) => (
<div style={{backgroundImage:`url(../../../public/assets//'${imgName}')`}} className="menu-item">
<div className="content">
<h1 className="title">{title}</h1>
<span>buy now</span>
</div>
</div>
)
export default MenuItem;
You can try it:
<div style={{backgroundImage:`url(require(../../../public/assets//'${imgName}'))`}} className="menu-item">
<div className="content">
<h1 className="title">{title}</h1>
<span>buy now</span>
</div>
</div>

Render Objects in Array in React HOC

I have the following React class:
import React from 'react';
import { withTranslation, WithTranslation } from 'react-i18next';
interface State {
payouts: any;
}
interface Props extends WithTranslation {}
class Payout extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
payouts: [
{id: 'PO_3', owner: 'OWNER1', amount: 89},
{id: 'PO_3', owner: 'OWNER2', amount: 150},
{id: 'PO_4', owner: 'OWNER3', amount: 135}
]
};
}
render() {
return (
<div>
{
this.state.payouts.map((payout:any) => (
Object.entries(payout).map((val: any)=> (
<li>{val.id} - {val.owner} - {val.amount}</li>
))
))
}
</div>
);
}
}
export default withTranslation()(Payout);
I am trying to render my state as a <li> element but I do net get any data shown.
Also would be payouts: object[] correct for the interface?
I do net get any data shown
Calling Object.entries will give you the following return value:
console.log(Object.entries({id: 'PO_4', owner: 'OWNER3', amount: 135}))
It's an array of arrays containing the property name and value. Of course these arrays don't have an id, owner or amount properties.
You don't want any of that. payout is already the object you want to access. Just remove that call:
return (
<div>
{
this.state.payouts.map((payout:any) => (
<li>{payout.id} - {payout.owner} - {payout.amount}</li>
))
}
</div>
);

Can i use the same component inside component in react?

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

How to render an array of objects in React?

could you please tell me how to render a list in react js.
I do like this
https://plnkr.co/edit/X9Ov5roJtTSk9YhqYUdp?p=preview
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
hello
</div>
);
}
}
You can do it in two ways:
First:
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>);
return (
<div>
{listItems }
</div>
);
}
Second: Directly write the map function in the return
render() {
const data =[{"name":"test1"},{"name":"test2"}];
return (
<div>
{data.map(function(d, idx){
return (<li key={idx}>{d.name}</li>)
})}
</div>
);
}
https://facebook.github.io/react/docs/jsx-in-depth.html#javascript-expressions
You can pass any JavaScript expression as children, by enclosing it within {}. For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = ['finish doc', 'submit pr', 'nag dan to review'];
return (
<ul>
{todos.map((message) => <Item key={message} message={message} />)}
</ul>
);
}
class First extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [{name: 'bob'}, {name: 'chris'}],
};
}
render() {
return (
<ul>
{this.state.data.map(d => <li key={d.name}>{d.name}</li>)}
</ul>
);
}
}
ReactDOM.render(
<First />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Shubham's answer explains very well. This answer is addition to it as per to avoid some pitfalls and refactoring to a more readable syntax
Pitfall : There is common misconception in rendering array of objects especially if there is an update or delete action performed on data. Use case would be like deleting an item from table row. Sometimes when row which is expected to be deleted, does not get deleted and instead other row gets deleted.
To avoid this, use key prop in root element which is looped over in JSX tree of .map(). Also adding React's Fragment will avoid adding another element in between of ul and li when rendered via calling method.
state = {
userData: [
{ id: '1', name: 'Joe', user_type: 'Developer' },
{ id: '2', name: 'Hill', user_type: 'Designer' }
]
};
deleteUser = id => {
// delete operation to remove item
};
renderItems = () => {
const data = this.state.userData;
const mapRows = data.map((item, index) => (
<Fragment key={item.id}>
<li>
{/* Passing unique value to 'key' prop, eases process for virtual DOM to remove specific element and update HTML tree */}
<span>Name : {item.name}</span>
<span>User Type: {item.user_type}</span>
<button onClick={() => this.deleteUser(item.id)}>
Delete User
</button>
</li>
</Fragment>
));
return mapRows;
};
render() {
return <ul>{this.renderItems()}</ul>;
}
Important : Decision to use which value should we pass to key prop also matters as common way is to use index parameter provided by .map().
TLDR; But there's a drawback to it and avoid it as much as possible and use any unique id from data which is being iterated such as item.id. There's a good article on this - https://medium.com/#robinpokorny/index-as-a-key-is-an-anti-pattern-e0349aece318
Try this below code in app.js file, easy to understand
function List({}) {
var nameList = [
{ id: "01", firstname: "Rahul", lastname: "Gulati" },
{ id: "02", firstname: "Ronak", lastname: "Gupta" },
{ id: "03", firstname: "Vaishali", lastname: "Kohli" },
{ id: "04", firstname: "Peter", lastname: "Sharma" }
];
const itemList = nameList.map((item) => (
<li>
{item.firstname} {item.lastname}
</li>
));
return (
<div>
<ol style={{ listStyleType: "none" }}>{itemList}</ol>
</div>
);
}
export default function App() {
return (
<div className="App">
<List />
</div>
);
}
import React from 'react';
class RentalHome extends React.Component{
constructor(){
super();
this.state = {
rentals:[{
_id: 1,
title: "Nice Shahghouse Biryani",
city: "Hyderabad",
category: "condo",
image: "http://via.placeholder.com/350x250",
numOfRooms: 4,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 43
},
{
_id: 2,
title: "Modern apartment in center",
city: "Bangalore",
category: "apartment",
image: "http://via.placeholder.com/350x250",
numOfRooms: 1,
shared: false,
description: "Very nice apartment in center of the city.",
dailyPrice: 11
},
{
_id: 3,
title: "Old house in nature",
city: "Patna",
category: "house",
image: "http://via.placeholder.com/350x250",
numOfRooms: 5,
shared: true,
description: "Very nice apartment in center of the city.",
dailyPrice: 23
}]
}
}
render(){
const {rentals} = this.state;
return(
<div className="card-list">
<div className="container">
<h1 className="page-title">Your Home All Around the World</h1>
<div className="row">
{
rentals.map((rental)=>{
return(
<div key={rental._id} className="col-md-3">
<div className="card bwm-card">
<img
className="card-img-top"
src={rental.image}
alt={rental.title} />
<div className="card-body">
<h6 className="card-subtitle mb-0 text-muted">
{rental.shared} {rental.category} {rental.city}
</h6>
<h5 className="card-title big-font">
{rental.title}
</h5>
<p className="card-text">
${rental.dailyPrice} per Night · Free Cancelation
</p>
</div>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
}
export default RentalHome;
Try this:
class First extends React.Component {
constructor (props){
super(props);
}
render() {
const data =[{"name":"test1"},{"name":"test2"}];
const listItems = data.map((d) => <li key={d.name}>{d.name}</li>;
return (
<div>
{listItems}
</div>
);
}
}

Categories

Resources