Render Objects in Array in React HOC - javascript

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>
);

Related

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>
);
}

union for array of object in typescript?

How to extends an property in array of object in typescript?
I have below react code:
interface List {
id: string;
}
interface AppProps {
list: List[];
}
const App: React.FC<AppProps> = ({ list }) => {
const [listCustom, setListCustom] = React.useState<List[]>([]);
React.useEffect(() => {
setListCustom([
{
id: "3",
newProperty: "new" //issue is here, how to extend List to have newProperty without modifying List?
}
]);
}, []);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
</div>
);
};
export default App;
In here
React.useEffect(() => {
setListCustom([
{
id: "3",
newProperty: "new" //issue is here, how to extend List to have newProperty without modifying List?
}
]);
}, []);
I have to set new property to List, but I don't want to modify List because it's tied to the AppProps. How can I 'extends' it in line const [listCustom, setListCustom] = React.useState<List[]>([]);?
It doesn't make sense to create a duplicated List2 like
interface List2 {
id: string;
newProperty: string
}
You can either extend the list interface:
interface List2 extends List {
newProperty: string;
}
Or you can use an intersection type:
type List2 = List & { newProperty: string }
The interface can't be done inline, but the intersection can be:
const [listCustom, setListCustom] = React.useState<(List & { newProperty: string })[]>([]);

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

TypeError: Cannot read property 'toLowerCase' of undefined in react

I am writing a program where items are printing in a table component and a search bar is given. Initially I had written all the components into a single component(App.js).
But now I am trying to split it into App, Table and Search
While printing the values through props into Table I am getting an error:
TypeError: Cannot read property 'toLowerCase' of undefined
Code:
App.js
import React, { Component } from 'react';
import './App.css';
import Table from './components/Table';
import Search from './components/Search';
const list = [
{
title: 'React',
url: 'https://facebook.github.io/react/',
author: 'Jordan Walke',
num_comments: 3,
points: 4,
objectID: 0,
},
{
title: 'Redux',
url: 'https://github.com/reactjs/redux',
author: 'Dan Abramov, Andrew Clark',
num_comments: 2,
points: 5,
objectID: 1,
},
{
title: 'Redux',
url: 'https://github.com/reactjs/redux',
author: 'Dan Abramov, Andrew Clark',
num_comments: 2,
points: 5,
objectID: 2,
},
{
title: 'Redux',
url: 'https://github.com/reactjs/redux',
author: 'Dan Abramov, Andrew Clark',
num_comments: 2,
points: 5,
objectID: 3,
},
];
//will print the above data through map function
//iteratre through item object and will print each property
//will print out
class App extends Component {
constructor(){
super();
this.state={
list,
searchText:''
}
this.onDismiss=this.onDismiss.bind(this);
this.onSearchChange=this.onSearchChange.bind(this);
//this.isSearched=this.isSearched.bind(this);
}
//to add a delete button
onDismiss=(id)=>{
//filter out item array and return results with no matched id
const deleteList=this.state.list.filter(item=>item.objectID!==id);
//setting state of list to lastest deleteList
this.setState({
list:deleteList
})
}
//to add a search bar
onSearchChange=(e)=>{
//set state to value in search bar
this.setState({
[e.target.name]:e.target.value
})
}
render() {
const {list,searchText}=this.state;
return(
<div>
<Table
list={list}
onDismiss={this.onDismiss}/>
<Search
searchText={searchText}
onSearchChange={this.onSearchChange}/>
</div>
)
}
}
export default App;
Table.js
import React, { Component } from 'react';
class Table extends Component {
render() {
const {list,searchText}=this.props;
return(
<div>
{/*Filter out item title and search title and give away results from item array */}
{list.filter((item)=>{
{/*The includes() method determines whether an array includes a certain value among its entries
, returning true or false as appropriate. */}
return item.title.toLowerCase().includes(searchText.toLowerCase());}).map((item)=>{
return(
<div key={item.objectID}>
{item.objectID}
{item.title}
<span>{item.author}</span>
<span>{item.num_comments}</span>
<span>{item.points}</span>
<button onClick={()=>this.onDismiss(item.objectID)}>delete</button>
</div>
)})}
</div>
)
}
}
export default Table;
Search.js
import React, { Component } from 'react';
class Search extends Component {
render() {
const {searchText,onSearchChange}=this.props;
return(
<div>
<input name="searchText" value={searchText}onChange={onSearchChange} type="text"></input>
</div>
)
}
}
export default Search;
Solved
I didn't pass searchText to the table that's why it was giving an error
<Table
list={list}
onDismiss={this.onDismiss}
searchText={searchText}/>

How do I load data file to state array in react?

I'm new to react.And I'm trying to load data file to a state array instead of directly placing array of data in the state.Below I've placed the code.But this doesn't display the data.
App.js
import React, { Component } from 'react';
import Projects from './Components/Projects';
import data from './data/data'
class App extends Component {
constructor(){
super();
this.state = {
myArrays: [{data}]
}
}
render() {
return (
<div className="App">
<Projects myArrays = {this.state.myArrays} />
</div>
);
}
}
export default App;
It works if I replace
<Projects myArrays = {this.state.myArrays} /> with <Projects myArrays = {data} />
What is the difference between doing this two? And why doesn't it load data with
<Projects myArrays = {this.state.myArrays} />
Project.js
import React, { Component } from 'react';
class Projects extends Component {
render() {
let projectItems;
projectItems = this.props.myArrays.map((project,i) =>{
return(
<li key = {i}>{project.title}</li>
);
});
return (
<ul>
{projectItems}
</ul>
);
}
}
export default Projects;
data.js
export default [
{
title: "Obama set for first political event since leaving office",
category: "politics"
},
{
title: 'La Liga refuse to accept PSG payment for Barcelona striker Neymar',
category: "sports"
},
{
title: "Virtu Financial closes KCG's European prop trading business",
category: "business"
}
]
The difference between
<Projects myArrays = {this.state.myArrays} />
and
<Projects myArrays = {data} />
is the way you are assigning data to the state
this.state = {
myArrays: [{data}]
}
This will result in this.state.myArrays which looks like
[{data: [
{
title: "Obama set for first political event since leaving office",
category: "politics"
},
{
title: 'La Liga refuse to accept PSG payment for Barcelona striker Neymar',
category: "sports"
},
{
title: "Virtu Financial closes KCG's European prop trading business",
category: "business"
}
]
}]
Replace it with
this.state = {
myArrays: data
}
and your first version will also work

Categories

Resources