I have a react class component displaying array of objects. However, when i render to display the data i get duplicate data. How can i remove the duplicates.
Customer.js
this.state = {
customer:[
{ id: 1, createdAt: "2023-01-22T05:19:45.943Z" },
{ id: 1, createdAt: "2023-01-19T02:19:45.943Z" },
{ id: 2, createdAt: "2023-01-18T05:30:45.943Z" },
],
};
componentDidMount() {
axios
.get("http://localhost:4000/customer/show", {
responseType: "json"
})
.then(response => {
this.setState({ customer: response.data });
});
}
.....................................
render() {
return(
{
this.state.customer?.map((item) => {
return (
<div>
<div key={ item.id }> Time of Visit: {moment(item.createdAt).format('hh:mm A')}
</div>
</div>
);
})
})}
Output
Time of Visit: 5:19 PM
Time of Visit: 2:19 PM
Time of Visit: 5:30 PM
Time of Visit: 5:30 PM
When i render the array of objects i get duplicate values. How can i change this code to display only unique values. Thanks in advance
This is the best way to filter out the repetitive value:
const ids = demoArray.map((d) => d.id)
const filteredResponse = demoArray.filter(
({ id }, index) => !ids.includes(id, index + 1)
So with your code it should be like this:
this.state = {
customer:[
{ id: 1, createdAt: "2023-01-22T05:19:45.943Z" },
{ id: 1, createdAt: "2023-01-19T02:19:45.943Z" },
{ id: 2, createdAt: "2023-01-18T05:30:45.943Z" },
],
};
componentDidMount() {
axios
.get("http://localhost:4000/customer/show", {
responseType: "json"
})
.then(response => {
const ids = response.data.map((d) => d.id)
const filteredResponse = response.data.filter(
({ id }, index) => !ids.includes(id, index + 1)
)
this.setState({ customer: filteredResponse });
});
}
render() {
return(
{this.state.customer?.map((item) => (
<div>
<div key={ item.id }> Time of Visit:
{moment(item.createdAt).format('hh:mm A')}
</div>
</div>
)
)
)
}
You can use the array filter function to customize your output.
function filterToGetEachIdOnce(item, index) {
return customer.findIndex(customer => customer.id === item.id) === index)
}
render() {
const { customer = [] } = this.state
return customer
.filter(filterToGetEachIdOnce)
.map((item) => {
return (
<div>
<div key={ item.id }> Time of Visit: {moment(item.createdAt).format('hh:mm A')}
</div>
</div>
);
})
})}
I have extracted the filter function to make it clear that you can modify it as you wish.
Check out the following links for more information:
Array.prototype.filter
Array.prototype.findIndex
Related
I'm trying to achieve making a suspend user button via updating the values of the user the status to Suspended, but the problem is the status is defined but other values are undefined did I do something wrong or is there any way to update the values to make the other variable like a name not required?
This is what I mean:
This is my code:
const User = (props) => (
<>
<DropdownButton id="dropdown-basic-button" title="Action">
<Dropdown.Item>
<a
href="user"
onClick={() => {
props.onSubmit(props.user[0]);
}}
>
<i className="fas fa-trash"></i> Suspend
</a>
</Dropdown.Item>
</DropdownButton>
</>
);
export default class Users extends Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
this.state = { users: [] };
}
componentDidMount() {
axios
.get("http://localhost:5000/users/")
.then((response) => {
this.setState({ users: response.data });
})
.catch((error) => {
console.log(error);
});
}
onSubmit(id) {
const user = {
name: this.state.name,
password: this.state.password,
email: this.state.email,
storeName: this.state.storeName,
storeUrl: this.state.storeUrl,
date: this.state.date,
status: "Suspended",
};
console.log(user);
axios
.post("http://localhost:5000/users/update/" + id, user)
.then((res) => console.log(res.data));
}
userList(currentuser) {
return (
<User
user={currentuser}
key={currentuser[0]}
onSubmit={this.onSubmit}
/>
);
}
render() {
const columns = [
{
name: "_id",
options: {
display: false,
},
},
{
name: "name",
label: "Name",
options: {
filter: true,
sort: true,
},
},
{
name: "Action",
options: {
customBodyRender: (value, tableMeta, updateValue) => {
return <>{this.userList(tableMeta.rowData)}</>;
},
},
},
];
const { users } = this.state;
return (
<>
<MUIDataTable data={users} columns={columns} />
</>
);
}
}
You didn't define nor set the User's individual attributes' values in the state! So, no wonder they show up as undefined, when you try to read them...
The simplest solution would be:
onSubmit(id) {
//let user = this.state.users.find(user => user.id === id); // find by id
let user = this.state.users[id]; // find by index
if (user) {
user.status = 'Suspended';
console.log(user);
axios
.post("http://localhost:5000/users/update/" + id, user)
.then((res) => console.log(res.data));
}
}
I have a json file called by fetch request that looks like this:
[
{
"Infos": [
{
"id": {
"Id": "105254"
},
"total": 142854739
},
{
"id": {
"Id": "105255"
},
"total": 112854739
},
{
"id": {
"Id": "105256"
},
"total": 132854739
},
{
"id": {
"Id": "106540"
},
"total": 122868818
}
]
}
]
I want to sort data based on total field ,but as you can see all objects are in another array called Infos and I can not to sort data like this:
Maindata.sort((a, b) => a.total - b.total);
How can I sort data based on total field that is in another an array?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null,
}
}
componentDidMount() {
fetch('/json.bc', {
method: 'get',
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'))
Maindata.sort((a, b) => a.Infos[i].total - b.Infos[i].total) // I want to sort data here /////
this.setState(state => ({
...state,
data: Maindata
}), () => {
this.reorganiseLibrary()
})
}).catch(error => console.error(error))
}
reorganiseLibrary = () => {
const { perPage, data } = this.state;
let library = data;
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
})
}
// Previous Page
previousPage = event => {
this.setState({
currentPage: this.state.currentPage - 1
})
}
// Next Page
nextPage = event => {
this.setState({
currentPage: this.state.currentPage + 1
})
}
// handle per page
handlePerPage = (evt) =>
this.setState({
perPage: evt.target.value
}, () => this.reorganiseLibrary());
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div>NOResult</div>
}
return library[currentPage - 1].map((item, i) => (
<div className="Wrapper">{this.renderInfo(item)}</div>
))
}
renderInfo(element){
let len =element.Infos.length
for (let i = 0; i < len; i++) {
return element.Infos[i].total
}
}
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div>
{this.renderLibrary()}
<ul id="page-numbers">
<li className="nexprevPage">
{currentPage !== 1 && (
<button onClick={this.previousPage}><span className="fa-backward"></span></button>
)}
</li>
<li className="controlsPage activeCnt">{this.state.currentPage}</li>
<li className="restControls">...</li>
<li className="controlsPage">{this.state.maxPage}</li>
<li className="nexprevPage">
{(currentPage < maxPage) && (
<button onClick={this.nextPage}><span className="fa-forward"></span></button>
)}
</li>
</ul>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('Result'))
You can sort the inner field by mapping over the outer array and sorting the inner one like
Maindata = Maindata.map((data) => ({Infos: data.Infos.sort((a, b) => a.total - b.total)}))
The code below shows each user info on users list button click.
Now I want fetch each users record from database on users list button click.
In the open() function, I have implemented the code below
open = (id,name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: 'id',
uname: 'name'
};
this.setState({ loading_image: true }, () => {
axios.post("http://localhost/data.php", { user_data })
.then(response => {
this.setState({
chatData1: response.data[0].id,
chatData: response.data,
loading_image: false
});
console.log(this.state.chatData);
alert(this.state.chatData1);
})
.catch(error => {
console.log(error);
});
});
}
In class OpenedUser(), I have initialize in the constructor the code below
chatData: []
In the render method have implemented the code
<b> Load Message from Database for each user ({this.state.chatData1})</b>
<div>
{this.state.chatData.map((pere, i) => (<li key={i}>{pere.lastname} - {pere.id}----- {pere.username}</li>))}
</div>
Here is my Issue:
My problem is that the Axios Api is getting the result but am not seeing any result in the render method.
but I can see it in the console as per code below
Array(1)
0: {id: "1", firstname: "faco", lastname: "facoyo"}
length: 1
Here is an example of json api response.
[{"id":"1","firstname":"faco","lastname":"facoyo"}]
Here is the full code
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import { Link } from 'react-router-dom';
import axios from 'axios';
class User extends React.Component {
open = () => this.props.open(this.props.data.id, this.props.data.name);
render() {
return (
<React.Fragment>
<div key={this.props.data.id}>
<button onClick={() => this.open(this.props.data.id,this.props.data.name)}>{this.props.data.name}</button>
</div>
</React.Fragment>
);
}
}
class OpenedUser extends React.Component {
constructor(props) {
super(props);
this.state = {
chatData: [],
hidden: false,
};
}
componentDidMount(){
} // close component didmount
toggleHidden = () =>
this.setState(prevState => ({ hidden: !prevState.hidden }));
close = () => this.props.close(this.props.data.id);
render() {
return (
<div key={this.props.data.id} style={{ display: "inline-block" }}>
<div className="msg_head">
<button onClick={this.close}>close</button>
<div>user {this.props.data.id}</div>
<div>name {this.props.data.name}</div>
{this.state.hidden ? null : (
<div className="msg_wrap">
<div className="msg_body">Message will appear here</div>
<b> Load Message from Database for each user ({this.state.chatData1}) </b>
<div>
{this.state.chatData.map((pere, i) => (
<li key={i}>
{pere.lastname} - {pere.id}----- {pere.username}
</li>
))}
</div>
</div>
)}
</div>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
shown: true,
activeIds: [],
data: [
{ id: 1, name: "user 1" },
{ id: 2, name: "user 2" },
{ id: 3, name: "user 3" },
{ id: 4, name: "user 4" },
{ id: 5, name: "user 5" }
],
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
open = (id,name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: 'id',
uname: 'name'
};
this.setState({ loading_image: true }, () => {
axios.post("http://localhost/apidb_react/search_data.php", { user_data })
.then(response => {
this.setState({
chatData1: response.data[0].id,
chatData: response.data,
loading_image: false
});
console.log(this.state.chatData);
alert(this.state.chatData1);
})
.catch(error => {
console.log(error);
});
});
// end axios api call
this.setState((prevState) => ({
activeIds: prevState.activeIds.find((user) => user === id)
? prevState.activeIds
: [...prevState.activeIds, id]
}));
}
close = id => {
this.setState((prevState) => ({
activeIds: prevState.activeIds.filter((user) => user !== id),
}));
};
renderUser = (id) => {
const user = this.state.data.find((user) => user.id === id);
if (!user) {
return null;
}
return (
<OpenedUser key={user.id} data={user} close={this.close}/>
)
}
renderActiveUser = () => {
return (
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{this.state.activeIds.map((id) => this.renderUser(id)) }
</div>
);
};
render() {
return (
<div>
{this.state.data.map(person => (
<User key={person.id} data={person} open={this.open} />
))}
{this.state.activeIds.length !== 0 && this.renderActiveUser()}
</div>
);
}
}
The problem is you're making the request in the App component and storing in state but you're trying to access the state in a child component so it will never actually read the data.
To fix this you need to pass in the chat data via prop
<OpenedUser
chatData={this.state.chatData}
key={user.id}
data={user}
close={this.close}
/>
Note: In my runnable example, I've replaced your api endpoint with a mock api promise.
const mockApi = () => {
return new Promise((resolve, reject) => {
const json = [{ id: "1", firstname: "faco", lastname: "facoyo" }];
resolve(json);
});
};
class User extends React.Component {
open = () => this.props.open(this.props.data.id, this.props.data.name);
render() {
return (
<React.Fragment>
<div key={this.props.data.id}>
<button
onClick={() => this.open(this.props.data.id, this.props.data.name)}
>
{this.props.data.name}
</button>
</div>
</React.Fragment>
);
}
}
class OpenedUser extends React.Component {
constructor(props) {
super(props);
this.state = {
hidden: false
};
}
componentDidMount() {} // close component didmount
toggleHidden = () =>
this.setState(prevState => ({ hidden: !prevState.hidden }));
close = () => this.props.close(this.props.data.id);
render() {
return (
<div key={this.props.data.id} style={{ display: "inline-block" }}>
<div className="msg_head">
<button onClick={this.close}>close</button>
<div>user {this.props.data.id}</div>
<div>name {this.props.data.name}</div>
{this.state.hidden ? null : (
<div className="msg_wrap">
<div className="msg_body">Message will appear here</div>
<b>
{" "}
Load Message from Database for each user ({this.state.chatData1}
){" "}
</b>
<ul>
{this.props.chatData.map((pere, i) => (
<li key={i}>
{pere.lastname} - {pere.id}----- {pere.username}
</li>
))}
</ul>
</div>
)}
</div>
</div>
);
}
}
class App extends React.Component {
constructor() {
super();
this.state = {
shown: true,
chatData: [],
activeIds: [],
data: [
{ id: 1, name: "user 1" },
{ id: 2, name: "user 2" },
{ id: 3, name: "user 3" },
{ id: 4, name: "user 4" },
{ id: 5, name: "user 5" }
]
};
}
toggle() {
this.setState({
shown: !this.state.shown
});
}
open = (id, name) => {
alert(id);
alert(name);
//start axios api call
const user_data = {
uid: "id",
uname: "name"
};
// this.setState({ loading_image: true }, () => {
// axios
// .post("http://localhost/apidb_react/search_data.php", { user_data })
// .then(response => {
// this.setState({
// chatData1: response.data[0].id,
// chatData: response.data,
// loading_image: false
// });
// console.log(this.state.chatData);
// alert(this.state.chatData1);
// })
// .catch(error => {
// console.log(error);
// });
// });
this.setState({ loading_image: true }, () => {
mockApi().then(data => {
this.setState({
chatData1: data[0].id,
chatData: data,
loading_image: false
});
});
});
// end axios api call
this.setState(prevState => ({
activeIds: prevState.activeIds.find(user => user === id)
? prevState.activeIds
: [...prevState.activeIds, id]
}));
};
close = id => {
this.setState(prevState => ({
activeIds: prevState.activeIds.filter(user => user !== id)
}));
};
renderUser = id => {
const user = this.state.data.find(user => user.id === id);
if (!user) {
return null;
}
return (
<OpenedUser
chatData={this.state.chatData}
key={user.id}
data={user}
close={this.close}
/>
);
};
renderActiveUser = () => {
return (
<div style={{ position: "fixed", bottom: 0, right: 0 }}>
{this.state.activeIds.map(id => this.renderUser(id))}
</div>
);
};
render() {
return (
<div>
{this.state.data.map(person => (
<User key={person.id} data={person} open={this.open} />
))}
{this.state.activeIds.length !== 0 && this.renderActiveUser()}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I see a few missing points in your code namely you are using li without ul which is a kind of invalid markup, then you have mapping for .username which is undefined field according to response which may also throw error.
Reactjs not updating the new value of product_number. I knew that similar question has been asked but am having hard time trying to resolve this.
The Reactjs code below displays provisions records from the arrays.
Now I need to update and replace the value the product_number from 001 to 006.
To this effect, I have added an update button which fetch the product_number from the Axios Call.
My problem is that product_number is not updated with 006 when the button is clicked.
Here is the json response of Axios Call for product_number updates
product_number.json
[{"product_number":"006"}]
Here is the code
import React, { Component, Fragment } from "react";
import { render } from "react-dom";
import axios from 'axios';
class Application extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
loading: false
};
}
componentDidMount() {
this.setState({
data: [
{"provision_id":"1","provision":"Milk","category":[{"category_id":"1","category_price":"100 USD","product":[{"product_id":"1","product_number":"001"}] }]}
],
});
}
// Get and update New Product number of Milk
handleNewProductNumber(prod_id) {
alert(prod_id);
const prod_data = {
prod_id: prod_id};
axios
.get("http://localhost/provision/product_number.json", { prod_data })
.then(response => {
const newData = this.state.data.map(store => {
//if (product.product_id !== prod_id) return product;
return {
...store,
product: store.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
}
)
};
});
this.setState(state => ({
data: newData
}));
console.log(response.data[0].category_price);
})
.catch(error => {
console.log(error);
});
}
render() {
return (
<span>
<label>
<ul>
{this.state.data.map((store) => {
return (
<div key={store.provision_id}>
<div><h1>Provision Store</h1> <br />
<b> Product: </b>{store.provision}
</div>
{store.category && store.category.map((cat) => {
return (
<div key={cat.category_id}>
<div><b>Prices:</b> {cat.category_price}
</div>
{cat.product && cat.product.map((prod) => <div key={prod.product_id}>
<b>Product Number:</b> #{prod.product_number}
<br />
<input
type="button"
value="Get & Update New Product Number"
onClick={() => this.handleNewProductNumber(prod.product_id)}
/>
</div>)}
</div>
)
})}
</div>
)
})}
</ul>
</label>
</span>
);
}
}
Updated Section using map function
return {
...store,
category: store.category.map(
product: store.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
})
})
};
The problem is the same of the other question, you have an array of object, with inside another array of objects, in your state:
data: [
{
"provision_id": "1",
"provision": "Milk",
"category": [
{
"category_id": "1",
"category_price": "100 USD",
"product": [
{
"product_id": "1",
"product_number": "001"
}
]
}
]
}
]
To update the inner level, you have to traverse all the state tree:
return {
...store,
category: [{
...store.category,
product: [{
...store.category[0].product,
product_number: response.data[0].product_number
}]
}]
};
Edit after... well, your edit
Your updated piece of code isn't valid syntax:
return {
...store,
category: store.category.map(
product: store.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
}
)
})
};
The first store.category.map call takes a function which will be called with a single category as an argument.
You have to spread the category prior to shadow the product property:
return {
...store,
category: store.category.map(
category => ({
...category,
product: category.product.map(
product => {
if (product.product_id !== prod_id) return product
return { ...product, product_number: response.data[0].product_number }
}
)
})
)
};
I have a MultiSelect and a React Table..
the Select stores the values into value Array..
The way it is now i´m able to select ONE option and the table displays the data correctly. But, i´m looking to render a table for each selected option. How could i achieve something like this?
handleSelectChange (value) {
console.log('You\'ve selected:', value);
this.setState({ value: value }, () => this.fetchTable());
}
fetchTable() {
const url = 'http://localhost:8000/issues/from/';
const value = this.state.value;
const string = url+value;
fetch(string)
.then(function(response) {
return response.json();
})
.then((myJson) => this.setState({data: myJson.issues}));
}
componentDidMount() {
this.fetchData();
}
render() {
const filteredResult = this.state.boards.map(item => (
{
value: item.key,
label: item.name,
}
));
const filteredResult1 = this.state.data.map(item => (
{
name: item.fields,
id: item.id,
key: item.key,
}
));
return (
<div>
<Select
closeOnSelect={!stayOpen}
disabled={disabled}
multi
onChange={this.handleSelectChange}
options={filteredResult}
placeholder="Select Assignee(s)..."
removeSelected={this.state.removeSelected}
rtl={this.state.rtl}
simpleValue
value={value}
/>
<ResponseTable data={filteredResult1} />
</div>
);
}
}
How does your ResponseTable component look like? I guess you can just use the map function to loop and display the table rows. Sth like this:
const data = [{name: 'Test 1', id: 1, key: 'key_1'}, {name: 'Test 2', id: 2, key: 'key_2'}, {name: 'Test 3', id: 3, key: 'key_3'}];
_renderTableBody = () => {
return data.map((item) => (
return (
<TableRow>
<TableCell>item.name</TableCell>
<TableCell>item.id</TableCell>
<TableCell>item.key</TableCell>
</TableRow>
)
))
}
Then inside your render function, you can just replace this
<ResponseTable data={filteredResult1} />
into the code like this:
{this._renderTableHead()} // same method as _renderTableBody() to generate the table head title
{this._renderTableBody()}
Hope this can help!
Just keep some dummy key in state which as empty array initially. It will push the selected value of select option in to it. like below
constructor(props){
this.state = {
selectedValues: []
}
}
Alter your handleSelectChange like below. It needs to update the current selected value in this array
handleSelectChange (value) {
console.log('You\'ve selected:', value);
//this.setState({ value: value }, () => this.fetchTable());
let currentSelectedValue = this.state.selectedValues.filter(selected => selected == value)
//it will return a value if it is found otherwise empty array will be returned
if(currentSelectedValue.length == 0){
let updatedSelectedValue = this.state.selectedValues.push(value)
this.setState({ selectedValues: updatedSelectedValues }, () => this.fetchTable());
}
}
removeSelected (value) {
console.log('You\'ve selected:', value);
//this.setState({ value: value }, () => this.fetchTable());
let currentSelectedValue = this.state.selectedValues.filter(selected => selected !== value) //this will delete the removed option from array
this.setState({ selectedValues: currentSelectedValue }, () => this.fetchTable());
}
fetchTable() {
if( this.state.selectedValues.length > 0 ){
this.state.selectedValues.map((value)=>{
const url = 'http://localhost:8000/issues/from/';
const string = url+value;
fetch(string)
.then(function(response) {
return response.json();
})
.then((myJson) => this.setState({data: [...this.state.data, myJson.issues]})); //use spread operator to combine the result of each selectedValue
});
}
}
render() {
const filteredResult = this.state.boards.map(item => (
{
value: item.key,
label: item.name,
}
));
const filteredResult1 = this.state.data.map(item => (
{
name: item.fields,
id: item.id,
key: item.key,
}
));
return (
<div>
<Select
closeOnSelect={!stayOpen}
disabled={disabled}
multi
onChange={this.handleSelectChange}
options={filteredResult}
placeholder="Select Assignee(s)..."
removeSelected={this.state.removeSelected}
rtl={this.state.rtl}
simpleValue
value={value}
/>
this.state.data.map((item) => { // item here will hold the json object of { id: item.id, key: item.key, name: item.fields }
<ResponseTable data={item} />
})
</div>
);
}
}