Updating and Passing Data Using React Hooks - javascript

I am passing a list of articles via const ARTICLES from index.js to App.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
import registerServiceWorker from "./registerServiceWorker";
import { applyPolyfills, defineCustomElements } from "h8k-components/loader";
const ARTICLES = [
{
title: "A message to our customers",
upvotes: 12,
date: "2020-01-24",
},
{
title: "Alphabet earnings",
upvotes: 22,
date: "2019-11-23",
},
{
title: "Artificial Mountains",
upvotes: 2,
date: "2019-11-22",
},
{
title: "Scaling to 100k Users",
upvotes: 72,
date: "2019-01-21",
},
{
title: "the Emu War",
upvotes: 24,
date: "2019-10-21",
},
{
title: "What's SAP",
upvotes: 1,
date: "2019-11-21",
},
{
title: "Simple text editor has 15k monthly users",
upvotes: 7,
date: "2010-12-31",
},
];
ReactDOM.render(<App articles={ARTICLES} />, document.getElementById("root"));
registerServiceWorker();
applyPolyfills().then(() => {
defineCustomElements(window);
});
I then pass the same list of articles from App.js to components/Article.js using React Hooks to update the order of the articles based on their upvotes and date properties when their respective buttons are clicked. But the update never happens. I can see the articleList changes when the buttons are clicked via console.log, but the Article.js component does not re-render these changes.
import React, { useState } from "react";
import "./App.css";
import "h8k-components";
import Articles from "./components/Articles";
const title = "Sorting Articles";
function App({ articles }) {
const [articleList, setArticle] = useState(articles);
function onTopClicked() {
setArticle(
articleList.sort(function (a, b) {
return b.upvotes - a.upvotes;
})
);
console.log("top", articleList);
}
function onNewestClicked() {
setArticle(
articleList.sort(function (a, b) {
let dateA = new Date(a.date);
let dateB = new Date(b.date);
return dateB - dateA;
})
);
console.log("date", articleList);
}
return (
<div className="App">
<h8k-navbar header={title}></h8k-navbar>
<div className="layout-row align-items-center justify-content-center my-20 navigation">
<label className="form-hint mb-0 text-uppercase font-weight-light">
Sort By
</label>
<button
data-testid="most-upvoted-link"
onClick={onTopClicked}
className="small"
>
Most Upvoted
</button>
<button
onClick={onNewestClicked}
data-testid="most-recent-link"
className="small"
>
Most Recent
</button>
</div>
<Articles articles={articleList} />
</div>
);
}
export default App;
The Article.js component receives the articleList data via its props.
import React from "react";
function Articles({ articles }) {
return (
<div className="card w-50 mx-auto">
<table>
<thead>
<tr>
<th>Title</th>
<th>Upvotes</th>
<th>Date</th>
</tr>
</thead>
<tbody>
{articles.map((article, i) => (
<tr key={i} data-testid="article" key="article-index">
<td data-testid="article-title">{article.title}</td>
<td data-testid="article-upvotes">{article.upvotes}</td>
<td data-testid="article-date">{article.date}</td>
</tr>
))}
</tbody>
</table>
</div>
);
}
export default Articles;
Why won't the articles re-render the articleList data when the buttons from App.js are clicked so I can re-order my articles based on their upvotes and date properties?

The sort function does not create return a new array. It sorts in place and returns the same array. So the reference is still the same and the state is not updated.
You should make a copy of the sorted array and set it as a new state
setArticle(
[...articleList.sort(function (a, b) {
let dateA = new Date(a.date);
let dateB = new Date(b.date);
return dateB - dateA;
})]
);

Related

Image is not showing in React app using img tag

My image is not showing in React app. I am trying to fetch the path from JSON and pass the path using props in <img> tag.
Example JSON object with the product data:
let data = [
{
id: 1,
name: "Striped Slim Fit Shirt",
image: "./Assets/m1.jpg",
price: 1000,
category: "Men",
size: "XL",
inStock: true,
},
{
id: 2,
name: "Full Sleeves Slim Fit Shirt",
image: "./Assets/m2.jpg",
price: 2000,
category: "Men",
size: "L",
inStock: true,
},
];
export default data;
My parent component from which I am passing props.
import { Fragment } from "react";
import data from "../../DUMMY_DATA";
import ItemList from "./ItemList";
const HomePage = () => {
const availableItems = data.map((products) => (
<ItemList
key={products.id}
images={products.image}
name={products.name}
price={products.price}
category={products.category}
size={products.size}
/>
));
return (
<Fragment>
<div>{availableItems}</div>
</Fragment>
);
};
export default HomePage;
My child component. Here, console logging shows the correct path, but the <img> tag is not rendering it.
import { Fragment } from "react";
const ItemList = (props) => {
const { id, images, name, price, category, size, inStock } = props;
return (
<Fragment>
<div className="container text-center">
<div className="row row-cols-4" key={id}>
<div className="col">
<img src={images} />
</div>
<div className="col">{name}</div>
<div className="col">{size}</div>
<div className="col">{price}</div>
</div>
</div>
</Fragment>
);
};
export default ItemList;

Redux with redux toolkit: UI is not changing

I'm new to redux and redux toolkit in React.js. Trying my best to make my PET project to apply for a future job, but faced a problem. I'll try to describe it.
Firstly, the code. removeInvoice function in invoice-slice.js file:
import { createSlice } from "#reduxjs/toolkit";
import { INVOICES_LIST } from "../Pages/Invoice/InvoicesList";
const invoiceSlice = createSlice({
name: "invoice",
initialState: {
invoices: INVOICES_LIST,
},
reducers: {
addNewInvoice(state, action) {
const newItem = action.payload;
state.invoices.push({
id: newItem.id,
billFrom: newItem.bill_from,
billFromAddress: newItem.billFromAddress,
billTo: newItem.bill_to,
billToAddress: newItem.bill_to_address,
invoiceNumber: newItem.invoice_num,
});
console.log(newItem);
},
removeInvoice(state, action) {
const id = action.payload;
state.invoices = state.invoices.filter((item) => item.id !== id);
console.log(action);
console.log(state.invoices);
},
editInvoice() {},
},
});
export const invoiceActions = invoiceSlice.actions;
export default invoiceSlice;
INVOICES_LIST looks like this:
export const INVOICES_LIST = [
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Pineapple Inc.",
bill_to: "REDQ Inc.",
total_cost: "14630",
status: "Pending",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "A box of happiness",
unit_costs: "200",
unit: "14",
price: "2800",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "AMD Inc.",
bill_to: "Intel Inc.",
total_cost: "14630",
status: "Delivered",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "Unicorn Tears",
unit_costs: "500",
unit: "14",
price: "1700",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Apple Inc.",
bill_to: "Samsung",
total_cost: "14630",
status: "Shipped",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: {
item_name: "Rainbow Machine",
unit_costs: "700",
unit: "5",
price: "3500",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
},
];
AllInvoices.js file where i map invoices:
import React, { Fragment } from "react";
import { useDispatch, useSelector } from "react-redux";
import { uiActions } from "../../store/ui-slice";
// import { invoiceActions } from "../../store/invoice-slice";
import { INVOICES_LIST } from "../Invoice/InvoicesList";
import Wrapper from "../../UI/Wrapper";
import Card from "../../UI/Card";
import Footer from "../../UI/Footer";
import Button from "../../UI/Button";
// import InvoiceItemDescription from "./InvoiceItemDescription";
// import EditInvoiceItem from "./EditInvoiceItem";
import classes from "./AllInvoices.module.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faChevronDown } from "#fortawesome/free-solid-svg-icons";
// import AddInvoiceItem from "./AddInvoiceItem";
import { Link } from "react-router-dom";
import Invoice from "./Invoice";
const AllInvoices = (props) => {
// const { id } = props;
const dispatch = useDispatch();
const toggleSelectOptions = () => {
dispatch(uiActions.toggleSelectOptions());
};
// const removeInvoiceItem = (id) => {
// dispatch(invoiceActions.removeInvoice(id));
// };
const showMoreOptions = useSelector(
(state) => state.ui.selectOptionsIsVisible
);
// const invoice = useSelector((state) => state.invoices);
return (
<Fragment>
<Wrapper isShrinked={props.isShrinked}>
<Card>
<h1 className={classes.header}>Invoice</h1>
<div className={classes.content}>
<div className={classes["btn-wrapper"]}>
<Link to="/invoices/add-invoice">
<Button>Add Invoice</Button>
</Link>
</div>
<div className={classes.invoices}>
{showMoreOptions && (
<ul className={classes.list}>
<li>Select all invoices</li>
<li>Unselect all</li>
<li>Delete selected</li>
</ul>
)}
<table>
<colgroup>
<col className={classes.col1}></col>
<col className={classes.col2}></col>
<col className={classes.col3}></col>
<col className={classes.col4}></col>
<col className={classes.col5}></col>
<col className={classes.col6}></col>
<col className={classes.col7}></col>
</colgroup>
<thead className={classes["table-head"]}>
<tr>
<th className={classes.position}>
<span className={classes.checkbox}>
<input type="checkbox"></input>
</span>
<FontAwesomeIcon
icon={faChevronDown}
className={classes.chevron}
onClick={toggleSelectOptions}
/>
</th>
<th>
<span className={classes["thead-text"]}>Number</span>
</th>
<th>
<span className={classes["thead-text"]}>Bill From</span>
</th>
<th>
<span className={classes["thead-text"]}>Bill To</span>
</th>
<th>
<span className={classes["thead-text"]}>Total Cost</span>
</th>
<th>
<span className={classes["thead-text"]}>Status</span>
</th>
</tr>
</thead>
<tbody>
{INVOICES_LIST.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
</tbody>
</table>
</div>
</div>
</Card>
<Footer />
</Wrapper>
</Fragment>
);
};
export default AllInvoices;
And Invoice.js file where i should use removeInvoice:
import React from "react";
import classes from "./Invoice.module.css";
import { useDispatch } from "react-redux";
import { Link } from "react-router-dom";
import { invoiceActions } from "../../store/invoice-slice";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faTrash } from "#fortawesome/free-solid-svg-icons";
const Invoice = (props) => {
const { id, invoice_num, bill_from, bill_to, status } = props.invoiceItem;
const dispatch = useDispatch();
const removeInvoiceItem = () => {
dispatch(invoiceActions.removeInvoice(id));
};
return (
<tr className={classes.height}>
<td>
<span className={classes.checkbox}>
<input type="checkbox"></input>
</span>
</td>
<td>
<span>{invoice_num}</span>
</td>
<td>
<span>{bill_from}</span>
</td>
<td>
<span>{bill_to}</span>
</td>
<td>
<span>14300</span>
{/* This should be a dynamic value later */}
</td>
<td>
<span
className={`${
status === "Pending" ? classes["status-pending"] : ""
} ${status === "Delivered" ? classes["status-delivered"] : ""} ${
status === "Shipped" ? classes["status-shipped"] : ""
}`}
>
{status}
</span>
</td>
<td>
<div className={classes.buttons}>
<Link to={`/invoices/invoice-description/${id}`}>
<button className={classes["view-btn"]}>View</button>
</Link>
<button className={classes["delete-btn"]} onClick={removeInvoiceItem}>
<FontAwesomeIcon icon={faTrash} />
</button>
</div>
</td>
</tr>
);
};
export default Invoice;
Now, the issue. It seems to remove the invoice from an array, because array changes from 3 items to 2, and shows in a console payload with appropriate id of item which i wanted to remove by clicking on a button, but UI console.log here doesn't reflect the changes, there is still 3 invoice items instead of 2 or less. Anyone know what can be the problem?
I've already tried alot of variants, like to pass an id to a function like this:
const removeInvoiceItem = (id) => {
dispatch(invoiceActions.removeInvoice(id));
};
Tried to make it with curly braces:
const removeInvoiceItem = (id) => {
dispatch(invoiceActions.removeInvoice({ id }));
};
Also tried anonymous function here:
<button className={classes["delete-btn"]} onClick={() => removeInvoiceItem(id)}>
<FontAwesomeIcon icon={faTrash} />
</button>
And so on. I know that if UI doesn't change, then state is not changing, but, in my case, i overwrite the state like this:
state.invoices = state.invoices.filter((item) => item.id !== id);
So, i don't know what else to do. Thought of useSelector and tried it like this:
const invoice = useSelector((state) => state.invoices);
And in map function:
{invoice.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
But it was crashing the page and telling me this error: Uncaught TypeError: invoice.map is not a function.
So, i don't know what to do else. Please, help me!!!
P.s. I'm new in stackoveflow, so sorry if something wrong :)
The problem is that you're using the constant INVOICE_LIST to map your elements instead of the current state of the store.
You used INVOICE_LIST to initialize your slice, that's good. But then you did not use what you initialized, you simply used the constant, and that's why the UI remained constant.
You should use useSelector to access that state like so:
const invoiceList = useSelector(state => state.invoice.invoices)
This should be the correct syntaxe in your case:
state.sliceName.wantedProperty
Now when you map on "invoiceList" instead of "INVOICE_LIST", this should do the trick!
You aren't rerendering the INVOICE_LIST when it changes. You would want to have a useEffect or something similar that will rerender the component when the INVOICE_LIST changes to see any changes on the UI side.
Your problem is this:
{INVOICES_LIST.map((invoice, index) => (
<Invoice
key={index}
invoiceItem={{
id: invoice.id,
invoice_num: invoice.invoice_num,
bill_from: invoice.bill_from,
bill_to: invoice.bill_to,
status: invoice.status,
}}
/>
))}
This is rendering static content and will not change even when you make a change to the redux store. You need to change this to state that will rerender when it changes.

React Fuse Component error for default export

I have this code to add div to table onclick, but I have added it from Stack to a Fuse project which has its own template. Please have a look at this code, I think there is a very simple problem with it. I am new to React, and I don't understand, how can I export the class. Whatever I tried, there is an error on it. Here is the code:
const useStyles = makeStyles({
layoutRoot: {},
});
Class Mdf extends React.Component ({
getInitialState: function () {
return {
tablerows: [
{ fname: "Tom", lname: "Moody", age: 23 }
]
};
},
addRow: function () {
// add new data from here
var newdata = { fname: "Tom", lname: "Moody", age: 23 }
//take the existing state and concat the new data and set the state again
this.setState({ tablerows: this.state.tablerows.concat(newdata) });
},
rows: function () {
return this.state.tablerows.map(function (row, i) {
return (<tr key={i}>
<td>{row.fname}</td>
<td>{row.lname}</td>
<td>{row.age}</td>
</tr>);
});
},
render: function () {
const classes = useStyles();
return (
<FusePageSimple
classes={{
root: classes.layoutRoot,
}}
header={
<div className="p-24">
<h1>Site Details</h1>
</div>
}
contentToolbar={
<div className="px-24">
<h4>Content Toolbar22222</h4>
</div>
}
content={
<div className="p-24">
<div>
<table>
<tr>
<td> row 1 </td>
</tr>
<tr>
<td> row 2 </td>
</tr>
<tr>
<td> row 3 </td>
</tr>
{this.rows()}
</table>
<button id="addBtn" onClick={this.addRow}>ADD</button>
</div>
</div>
}
/>
);
}
});
// React.render(<Mdf />)
export default Mdf
And the error message which shows up is this:
Attempted import error: './Mdf' does not contain a default export (imported as 'Mdf').

A problem with react component(view) not updating but the state is updating

I am facing a bit of a problem. I have two components. One parent component that is called goals and under different instances of goal. I am updating state of the parent component by passing a function to its children. The state of the parent is updated however only one of the child who made the change apply the change they should be all the same
Goals
import UserGoal from "./UserGoal";
import { Button, Container, Form, InputGroup } from "react-bootstrap";
import React, { useState, useEffect } from "react";
import "./UserGoal.css";
import { Link } from "react-router-dom";
const UserGoals = () => {
var test = [
{
id: 1,
name: "Marriage",
icon: "Marriage.png",
isSelected:false,
style: "goal-category"
},
{
id: 2,
name: "Car",
icon: "Car.png",
isSelected:false,
style: "goal-category"
},
{
id: 3,
name: "Home",
icon: "Home.png",
isSelected:false,
style: "goal-category"
},
{
id: 4,
name: "Education",
icon: "Education.png",
isSelected:false,
style: "goal-category"
},
{
id: 5,
name: "Travel",
icon: "Travel.png",
isSelected:false,
style: "goal-category"
},
{
id: 6,
name: "Retirement",
icon: "Retirement.png",
isSelected:false,
style: "goal-category"
},
{
id: 7,
name: "Other",
icon: "Other.png",
isSelected:false,
style: "goal-category"
},
]
const [goals, setGoals] = useState(test)
const changeSelection = (id) => {
const newarr = goals.map((GoalType)=> {
if(GoalType.id===id){
GoalType.isSelected=true
GoalType.style= "goal-category2"
}
else {
GoalType.isSelected=false
GoalType.style= "goal-category"
}
return GoalType
})
forceUpdate(newarr)
console.log(goals);
}
const forceUpdate = React.useCallback((arr) => {
setGoals(arr);
}, []);
return (
<Container>
<h1>Your saving goal</h1>
<div className="goal-categories">
{goals.map((GoalType) => (
<UserGoal
id={GoalType.id}
name={GoalType.name}
icon={GoalType.icon}
isSelected={()=>GoalType.isSelected}
style={()=>GoalType.style}
key={GoalType.id}
onClick={changeSelection}
></UserGoal>
))}
</div>
<div className="reg-wrapper">
<div className="reg-inner">
<Form className="ctr-form">
<Form.Label>Amount</Form.Label>
<InputGroup className="mb-3">
<Form.Control
className="input"
type="number"
placeholder="0.00"
/>
<div className="input-group-text">SAR</div>
</InputGroup>
<Form.Label>Date</Form.Label>
<InputGroup className="mb-3">
<Form.Control className="input" type="date" />
</InputGroup>
<div className="btn">
<Link to="/expenses">
<Button id="btn btn-primary" className="dbtn">
Next
</Button>
</Link>
</div>
</Form>
</div>
</div>
</Container>
);
}
export default UserGoals
Goal
import React from "react";
import { useState } from "react";
import "./UserGoal.css";
import { useEffect } from "react";
export default function UserGoal({ id, name, icon, isSelected, style, onClick }) {
const [style_, setStyle_] = useState(style())
return (
<>
<div className="goal-category-container">
<div
onClick={()=>{
onClick(id);
setStyle_(style())
}}
className={style_}
>
<div className="icon-wrap">
<img src={"assets/" + icon} alt="Goal Icon" />
</div>
</div>
<div className="category-name">{name} </div>
</div>
</>
);
}
You call setStyle_ immediately after the callback, even though the effects of the callback are asynchronous. Ie, the style won't be updated yet because the patent is doing an asynchronous setState.
Instead send down style as a value, not a function. That way the child will react to updates. Also having style as state oh the child is unnecessary, since you can just rely on the prop.
Also, don't use mutation in your map function. Instead create new goal objects. And your React.useCallback is equivalent to using the setter directly, it can be removed.

How to map over an object which has a unique id for each object values and return the values to a React component

I am working on a redux project where I want to retrieve the values stored in API server.I want to store the data from the API in my redux store and then retrieve the values and display it in my react component.The data in the API server is in the form of an object but has a unique id for each value.So,in my case, the data is a list of posts.So, each post has a unique id and has all the other details like timestamp,post-title,post-author etc.This is how the default data from the API for posts looks like:
const defaultData = {
"8xf0y6ziyjabvozdd253nd": {
id: '8xf0y6ziyjabvozdd253nd',
timestamp: 1467166872634,
title: 'Udacity is the best place to learn React',
body: 'Everyone says so after all.',
author: 'thingtwo',
category: 'react',
voteScore: 6,
deleted: false,
commentCount: 2
},
"6ni6ok3ym7mf1p33lnez": {
id: '6ni6ok3ym7mf1p33lnez',
timestamp: 1468479767190,
title: 'Learn Redux in 10 minutes!',
body: 'Just kidding. It takes more than 10 minutes to learn technology.',
author: 'thingone',
category: 'redux',
voteScore: -5,
deleted: false,
commentCount: 0
}
}
Note: The "id" which is a random number here(like "8xf0y6ziyjabvozdd253nd") becomes an integer, i.e the 1st post gets the id 1 ,the 2nd gets 2.
So, I am able to store the data from posts API in my redux "Store". And I converted the posts object into an array(as we cannot map over an object) because I want to map over this array and show the data in my React component.But,I am not able to see the result of the array in my component,maybe that's because it has an id before each object in the array.This is how I am trying to map over the arrayand I do not get any error,but I do not see the results from the object in component.My component file looks like this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchPosts } from '../actions';
import _ from 'lodash';
class PostsIndex extends Component {
componentDidMount() {
this.props.dispatch(fetchPosts())
.then(() => {
this.setState({
loading : false
});
// console.log(this.props.posts.posts[0])
})
}
render() {
// console.log(this.props.posts.posts)
const obj = this.props.posts.posts;
let arr;
if (obj) {
arr = Object.values(obj); //Converting an Object into an array
}
console.log(arr); //returns the converted array from an object
return(
<div>
{
arr ?
<div>
{ arr.map(post =>
{
<div>
{post.title}
</div>
})
}
</div>
:
<div>
No Data
</div>
}
</div>
);
}
}
function mapStateToProps(state) {
return { posts: state.posts };
}
export default connect(mapStateToProps)(PostsIndex);
And when I console.log my state,the converted array looks like this:
When expanded looks like:
I want to retrieve almost all of the values from the above array.Can anyone please show me how to get the data from the array and map over the array to show the values in my React component?
You can keep your data as an object, and use Object.keys to get an array of keys, map over the keys, and use the keys to access nested objects. If you don't know the shape of your data source, you could use recursion.
Here is a working code sandbox example where I've taken your data source and turned it into a table to illustrate how to do so.
Here is the code:
import React from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
const defaultData = {
"8xf0y6ziyjabvozdd253nd": {
id: '8xf0y6ziyjabvozdd253nd',
timestamp: 1467166872634,
title: 'Udacity is the best place to learn React',
body: 'Everyone says so after all.',
author: 'thingtwo',
category: 'react',
voteScore: 6,
deleted: false,
commentCount: 2
},
"6ni6ok3ym7mf1p33lnez": {
id: '6ni6ok3ym7mf1p33lnez',
timestamp: 1468479767190,
title: 'Learn Redux in 10 minutes!',
body: 'Just kidding. It takes more than 10 minutes to learn technology.',
author: 'thingone',
category: 'redux',
voteScore: -5,
deleted: false,
commentCount: 0
}
}
const TableHeader = ({ fields }) => (
<thead>
<tr>
{
fields.map( field => <th key={ field }>{ field }</th>)
}
</tr>
</thead>
);
const TableBody = ({ data }) => (
<tbody>
{
Object.keys(data).map(
datum =>
<tr>
{
Object.keys(data[datum]).map(
field => <td>{data[datum][field]}</td>
)
}
</tr>
)
}
</tbody>
);
const App = () => (
<table>
<TableHeader fields={ Object.keys(defaultData[Object.keys(defaultData)[0]]) } />
<TableBody data={defaultData} />
</table>
);
render(<App />, document.getElementById('root'));
You need map your data. Something like this:
<div>
<ul>
{props.incomingDataArray.map((singleArrayItem, index) => {
return (
<li key="list + index">{singleArrayItem.commentCount}</li>
<li key="list + index">{singleArrayItem.timestamp}</li>
)
})
}
</ul>
<div>
you forgot return inside your map.
render() {
const obj = this.props.posts.posts;
let arr;
if (obj) {
arr = Object.values(obj); //Converting an Object into an array
}
return (
<div>
{ arr ?
<div>
{ arr.map(post => {
return (
<div key={post.id}>
{post.title}
</div>
)
})
}
</div> :
<div>
No Data
</div>
}
</div>
);
}
or, alternatively, drop the curly braces with a oneliner:
arr.map(post => (<div key={post.id}>
{post.title}
</div>
)
)
and don't forget the key attribute.
I also suggest you abstract way your dumb components. It'll make your code more readable.

Categories