I'm currently trying to create a component that show some of the state but show more once a button is clicked. Each time a button is clicked it should show 3 more items.
I tried a few different things, here is my current code: Any help and explanation is appreciated:
import React from 'react';
import { render } from 'react-dom';
class ShowSomeItems extends React.Component {
constructor() {
super()
this.state = {
cars: [
{ "name": "Audi", "country": "Germany" },
{ "name": "BMW", "country": "Germany" },
{ "name": "Chevrolet", "country": "USA" },
{ "name": "Citroen", "country": "France" },
{ "name": "Hyundai", "country": "South Korea" },
{ "name": "Mercedes-Benz", "country": "Germany" },
{ "name": "Renault", "country": "France" },
{ "name": "Seat", "country": "Spain" },
{ "name": "Dodge", "country": "USA" },
{ "name": "BMW", "country": "Germany" },
{ "name": "Tesla", "country": "USA" },
{ "name": "Volkswagen", "country": "Germany" },
{ "name": "Hyundai", "country": "South Korea" },
{ "name": "Jaguar", "country": "United Kingdom" },
{ "name": "GMC", "country": "USA" },
{ "name": "Bentley", "country": "United Kingdom" },
],
numberOfitemsShown: 5,
}
}
showMore = () => {
let numberToincrementBy = 3;
if(this.state.numberOfitemsShown < this.state.car.length){
itemsToShow = this.cars.slice(0, incremenrIndex)
numberToincrementBy+3
return itemsToShow
}
}
render() {
let itemsToShow = "Loading...";
if(this.state.numberOfitemsShown){
itemsToShow = for(let x = 0; x < 5; x++) {
<li key={x}>{this.state.cars[x]['name']}</li>
}
}
return (
<div>
<ul>
{itemsToShow}
</ul>
<button onClick={this.showMore}>
show more
</button>
</div>
);
}
}
render(<ShowSomeItems />, document.getElementById('root'));
A better approach in this case is to take advantage of component state to keep the current number of items you want to show and increment it with the button. It's cleaner and it goes well with the react way of defining UI. Example:
class ShowSomeItems extends React.Component {
constructor() {
super()
this.state = {
cars: [
{ "name": "Audi", "country": "Germany" },
{ "name": "BMW", "country": "Germany" },
{ "name": "Chevrolet", "country": "USA" },
{ "name": "Citroen", "country": "France" },
{ "name": "Hyundai", "country": "South Korea" },
{ "name": "Mercedes-Benz", "country": "Germany" },
{ "name": "Renault", "country": "France" },
{ "name": "Seat", "country": "Spain" },
{ "name": "Dodge", "country": "USA" },
{ "name": "BMW", "country": "Germany" },
{ "name": "Tesla", "country": "USA" },
{ "name": "Volkswagen", "country": "Germany" },
{ "name": "Hyundai", "country": "South Korea" },
{ "name": "Jaguar", "country": "United Kingdom" },
{ "name": "GMC", "country": "USA" },
{ "name": "Bentley", "country": "United Kingdom" },
],
numberOfitemsShown: 5,
}
}
showMore = () => {
if (this.state.numberOfitemsShown + 3 <= this.state.cars.length) {
this.setState(state => ({ numberOfitemsShown: state.numberOfitemsShown + 3 }));
} else {
this.setState({ numberOfitemsShown: this.state.cars.length })
}
}
render() {
const itemsToShow = this.state.cars
.slice(0, this.state.numberOfitemsShown)
.map(car => <li key={car.name}>{car.name}</li>);
return (
<div>
<ul>
{itemsToShow.length ? itemsToShow : "Loading..."}
</ul>
<button onClick={this.showMore}>
show more
</button>
</div>
);
}
}
EDIT
You can make the render method cleaner extracting itemsToShow into a component like this:
const Items = props => {
if (props.cars.length === 0) {
return "Loading..."
}
return props.cars
.slice(0, props.numberOfitemsShown)
.map(car => <li key={car.name}>{car.name}</li>)
}
class ShowSomeItems extends React.Component {
//rest excluded for brevity
render() {
return (
<div>
<ul>
<Items cars={this.state.cars} numberOfitemsShown={this.state.numberOfitemsShown} />
</ul>
<button onClick={this.showMore}>
show more
</button>
</div>
);
}
}
Those who require the functional component version, can check this. I have changed the class based component which #SrThompson written into a functional
import { useMemo, useState } from "react";
import "./styles.css";
const carsList = [
{ name: "Audi", country: "Germany" },
{ name: "BMW", country: "Germany" },
{ name: "Chevrolet", country: "USA" },
{ name: "Citroen", country: "France" },
{ name: "Hyundai", country: "South Korea" },
{ name: "Mercedes-Benz", country: "Germany" },
{ name: "Renault", country: "France" },
{ name: "Seat", country: "Spain" },
{ name: "Dodge", country: "USA" },
{ name: "BMW", country: "Germany" },
{ name: "Tesla", country: "USA" },
{ name: "Volkswagen", country: "Germany" },
{ name: "Hyundai", country: "South Korea" },
{ name: "Jaguar", country: "United Kingdom" },
{ name: "GMC", country: "USA" },
{ name: "Bentley", country: "United Kingdom" }
];
export default function App() {
const [cars] = useState(carsList);
const [numberOfitemsShown, setNumberOfItemsToShown] = useState(5);
const showMore = () => {
if (numberOfitemsShown + 3 <= cars.length) {
setNumberOfItemsToShown(numberOfitemsShown + 3);
} else {
setNumberOfItemsToShown(cars.length);
}
};
const itemsToShow = useMemo(() => {
return cars
.slice(0, numberOfitemsShown)
.map((car, index) => <li key={car.name + index}>{car.name}</li>);
}, [cars, numberOfitemsShown]);
return (
<div>
<ul>{itemsToShow.length ? itemsToShow : "Loading..."}</ul>
<button onClick={showMore}>show more</button>
</div>
);
}
Working codesandbox
Related
I am getting an array of objects from the server in the following format:
[
{
"country": "UK",
"name": "Battery Ltd 1",
"type": "contact"
},
{
"country": "USA",
"name": "Technologies Inc. 1",
"type": "contact"
},
{
"country": "",
"name": "Jayne Mansfield",
"type": "representative"
},
{
"country": "China",
"name": "Technologies Inc. 2",
"type": "contact"
},
{
"country": "",
"name": "Dan Borrington",
"type": "representative"
},
{
"country": "",
"name": "Susan Reedy",
"type": "representative"
}
]
However, I need to iterate over this array of objects and convert it to this format: I want to combine the CONTACT type with the following REPRESENTATIVE object or objects. That is, at the output, I would like to get such an array with arrays:
[
[
{
"country": "UK",
"name": "Battery Ltd 1",
"type": "contact"
}
],
[
{
"country": "USA",
"name": "Technologies Inc. 1",
"type": "contact"
},
{
"country": "",
"name": "Jayne Mansfield",
"type": "representative"
},
],
[
{
"country": "China",
"name": "Technologies Inc. 2",
"type": "contact"
},
{
"country": "",
"name": "Dan Borrington",
"type": "representative"
},
{
"country": "",
"name": "Susan Reedy",
"type": "representative"
}
]
]
You can go through the elements and create a group if element is a contact, and add to the group otherwise:
const data = [
{
"country": "UK",
"name": "Battery Ltd 1",
"type": "contact"
},
{
"country": "USA",
"name": "Technologies Inc. 1",
"type": "contact"
},
{
"country": "",
"name": "Jayne Mansfield",
"type": "representative"
},
{
"country": "China",
"name": "Technologies Inc. 2",
"type": "contact"
},
{
"country": "",
"name": "Dan Borrington",
"type": "representative"
},
{
"country": "",
"name": "Susan Reedy",
"type": "representative"
}
]
const result = data.reduce( (r, e) => (e.type === 'contact' ? r.push([e]) : r[r.length -1].push(e), r), [])
console.log(result)
const array = []
let current = []
let hasRepresentative = false
for (const item of getItems()) {
if (current.length === 0) {
current.push(item)
continue
}
if (hasRepresentative && item.type === 'contact') {
array.push(current)
current = [item]
continue
}
current.push(item)
hasRepresentative = true
}
array.push(current)
console.log(array)
function getItems() { return [
{
"country": "UK",
"name": "Battery Ltd 1",
"type": "contact"
},
{
"country": "USA",
"name": "Technologies Inc. 1",
"type": "contact"
},
{
"country": "",
"name": "Jayne Mansfield",
"type": "representative"
},
{
"country": "China",
"name": "Technologies Inc. 2",
"type": "contact"
},
{
"country": "",
"name": "Dan Borrington",
"type": "representative"
},
{
"country": "",
"name": "Susan Reedy",
"type": "representative"
}
]
}
I'd like to take this array of objects, where some objects contain arrays of a similar schema, and create a new array where they're all on the same level.
[
{
"name": "United States",
"slug": "united-states",
"states":[
{
"name": "Arizona",
"slug": "arizona"
},
{
"name": "California",
"slug": "california"
}
]
},
{
"name": "Canada",
"slug": "canada",
}
]
This should be the end result:
[
{
"name": "United States",
"slug": "united-states"
},
{
"name": "Arizona",
"slug": "arizona"
},
{
"name": "California",
"slug": "california"
},
{
"name": "Canada",
"slug": "canada",
}
]
Using Array#flatMap:
const data = [
{
"name": "United States",
"slug": "united-states",
"states":[
{ "name": "Arizona", "slug": "arizona" },
{ "name": "California", "slug": "california" }
]
},
{ "name": "Canada", "slug": "canada" }
];
const res = data.flatMap(({ name, slug, states = [] }) => ([
{ name, slug },
...states
]));
console.log(res);
You could create an iterator for traversing the tree, and than consume that into an array. This works with deeper nesting levels, and does not need to know which property has the child records. It assumes that the property which has an Array value is holding the subtrees:
function * traverse(forest) {
for (const item of forest) {
const arrayKey = Object.entries(item).find(([k, v]) => Array.isArray(v))?.[0];
const { [arrayKey]: children, ...rest } = item;
yield rest;
if (children) yield * traverse(children);
}
}
const data = [{"name": "United States","slug": "united-states","states":[{ "name": "Arizona", "slug": "arizona" },{ "name": "California", "slug": "california" }]},{ "name": "Canada", "slug": "canada" }];
const res = [...traverse(data)];
console.log(res);
I have random cities list as below . How can I group and sort it with below criteria
SortAndGroup function should take input of the countryCode and sort accordingly with capitol city on each group at first position followed by cities in that country. Thank you for your help.
randonCities =
[
{
"name": "Delhi",
"countryCode": "IN",
"isCapitol": true
},
{
"name": "New York",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Birmingham",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "London",
"countryCode": "UK",
"isCapitol": true
},
{
"name": "Hyderabad",
"countryCode": "IN",
"isCapitol": false
},
{
"name": "Chicago",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Bristol",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Washington",
"countryCode": "USA",
"isCapitol": true
}
]
End Result should be
sortByCountry(USA, UK, IND) =
[
{
"name": "Washington",
"countryCode": "USA",
"isCapitol": true
},
{
"name": "Chicago",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "New York",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "London",
"countryCode": "UK",
"isCapitol": true
},
{
"name": "Birmingham",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Bristol",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Delhi",
"countryCode": "IN",
"isCapitol": true
},
{
"name": "Hyderabad",
"countryCode": "IN",
"isCapitol": false
}
]
You could get the order from an array (with corresponding country names) and sort by capitol.
const
sortByCountry = (...countries) => (a, b) =>
countries.indexOf(a.countryCode) - countries.indexOf(b.countryCode) ||
b.isCapitol - a.isCapitol,
array = [{ name: "Delhi", countryCode: "IN", isCapitol: true }, { name: "New York", countryCode: "USA", isCapitol: false }, { name: "Birmingham", countryCode: "UK", isCapitol: false }, { name: "London", countryCode: "UK", isCapitol: true }, { name: "Hyderabad", countryCode: "IN", isCapitol: false }, { name: "Chicago", countryCode: "USA", isCapitol: false }, { name: "Bristol", countryCode: "UK", isCapitol: false }, { name: "Washington", countryCode: "USA", isCapitol: true }];
array.sort(sortByCountry('USA', 'UK', 'IN'));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
ES5
var sortByCountry = function () {
var countries = Array.prototype.slice.call(arguments);
return function (a, b) {
return countries.indexOf(a.countryCode) - countries.indexOf(b.countryCode) ||
b.isCapitol - a.isCapitol;
}
},
array = [{ name: "Delhi", countryCode: "IN", isCapitol: true }, { name: "New York", countryCode: "USA", isCapitol: false }, { name: "Birmingham", countryCode: "UK", isCapitol: false }, { name: "London", countryCode: "UK", isCapitol: true }, { name: "Hyderabad", countryCode: "IN", isCapitol: false }, { name: "Chicago", countryCode: "USA", isCapitol: false }, { name: "Bristol", countryCode: "UK", isCapitol: false }, { name: "Washington", countryCode: "USA", isCapitol: true }];
array.sort(sortByCountry('USA', 'UK', 'IN'));
console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
In order to sort an array, you can use:
arr.sort([compareFunction])
So you would have to write a custom compareFunction
The compareFunction compares two any elements of the array and should return 1 if the first element is "bigger" or -1 if the first element is "smaller"
arr.sort((a, b) => (a > b) ? 1 : -1)
In this case our sorting function can receive any number of parameters, so we can access them in the arguments object. We can convert the arguments object into an array and use the indexOf function to compare the position of the country code in the array.
When the country code is the same, we check if one of the items is capitol.
randomCities =
[
{
"name": "Delhi",
"countryCode": "IN",
"isCapitol": true
},
{
"name": "New York",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Birmingham",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "London",
"countryCode": "UK",
"isCapitol": true
},
{
"name": "Hyderabad",
"countryCode": "IN",
"isCapitol": false
},
{
"name": "Chicago",
"countryCode": "USA",
"isCapitol": false
},
{
"name": "Bristol",
"countryCode": "UK",
"isCapitol": false
},
{
"name": "Washington",
"countryCode": "USA",
"isCapitol": true
}
]
function sortByCountry(){
var args = Array.from(arguments);
randomCities.sort( (a, b) => (args.indexOf(a.countryCode) == args.indexOf(b.countryCode)) ? (a.isCapitol ? -1 : 1) : ((args.indexOf(a.countryCode) > args.indexOf(b.countryCode)) ? 1 : -1));
return randomCities;
}
sortyByCountry('USA', 'UK', 'IN');
You could do it using Array.prototype.sort() method and sort the country code by creating an ordering array, then by capital and at last, by city name.
const sortByCountry = (data, order) =>
data.sort(
(x, y) =>
order.indexOf(x.countryCode) - order.indexOf(y.countryCode) ||
y.isCapitol - x.isCapitol ||
x.name.localeCompare(y.name)
);
const data = [
{
name: 'Delhi',
countryCode: 'IN',
isCapitol: true,
},
{
name: 'New York',
countryCode: 'USA',
isCapitol: false,
},
{
name: 'Birmingham',
countryCode: 'UK',
isCapitol: false,
},
{
name: 'London',
countryCode: 'UK',
isCapitol: true,
},
{
name: 'Hyderabad',
countryCode: 'IN',
isCapitol: false,
},
{
name: 'Chicago',
countryCode: 'USA',
isCapitol: false,
},
{
name: 'Bristol',
countryCode: 'UK',
isCapitol: false,
},
{
name: 'Washington',
countryCode: 'USA',
isCapitol: true,
},
];
const order = ['IND', 'USA', 'UK'];
console.log(sortByCountry(data, order));
I have a very basic API made with Django Rest Framework with an output as follows:
[
{
"name": "John",
"city": "chicago",
"age": "22"
},
{
"name": "Gary",
"city": "florida",
"age": "35"
},
{
"name": "Selena",
"city": "vegas",
"age": "18"
}
]
I want to convert it to the following format to simplify the usage of its data in charts.
{
"name": ["John", "Gary", "Selena"]
"city": ["chicago", "vegas", "florida"]
"age": ["22", "35", "18"]
}
Is there a simple way this can be done in Javascript (and Python just for curiosity)?
2. Can this be proactively solved by adjusting the Serializer or the ViewSet in DRF?
Javascript version:
const data = [
{
name: 'John',
city: 'chicago',
age: '22',
},
{
name: 'Gary',
city: 'florida',
age: '35',
},
{
name: 'Selena',
city: 'vegas',
age: '18',
},
];
const result = Object.keys(data[0]).reduce((obj, key) => {
obj[key] = data.map(_ => _[key]);
return obj;
}, {});
console.log(result);
In Python you could do it like this:
data = [
{
"name": "John",
"city": "chicago",
"age": "22"
},
{
"name": "Gary",
"city": "florida",
"age": "35"
},
{
"name": "Selena",
"city": "vegas",
"age": "18"
}
]
result = {}
for key in data[0]:
result[key] = []
for entry in data:
for key in entry:
result[key].append(entry[key])
print(result)
check this
data = [
{
"name": "John",
"city": "chicago",
"age": "22"
},
{
"name": "Gary",
"city": "florida",
"age": "35"
},
{
"name": "Selena",
"city": "vegas",
"age": "18"
}
]
output = []
name = []
city = []
age = []
for i in data:
name.append(i['name'])
city.append(i['city'])
age.append(i['age'])
output.append({"name":name,"city":city,"age":age})
print(output)
var json = [{
"city": "California",
"name": "Joe",
"age": 17
}, {
"city": "California",
"name": "Bob",
"age": 17
}, {
"city": "California",
"name": "Bob",
"age": 35
}, {
"city": "Texas",
"name": "Bob",
"age": 35
}, {
"city": "Florida",
"name": "Bob",
"age": 35
}
];
I just to no of occurence based on city value i.e output as below.
updatedjson=[{"name":"California","count":3},{"name":"Texas","count":1},{"name":"Florida","count":1}]
using any approah using lodash or javascript
Using Lodash, that would be:
const updatedJson = _(json)
.countBy('city')
.map((count, name) => ({ name, count }))
.value();
const json = [{"city":"California","name":"Joe","age":17},{"city":"California","name":"Bob","age":17},{"city":"California","name":"Bob","age":35},{"city":"Texas","name":"Bob","age":35},{"city":"Florida","name":"Bob","age":35}];
const updatedJson = _(json)
.countBy('city')
.map((count, name) => ({ name, count }))
.value();
console.log(JSON.stringify(updatedJson));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.min.js"></script>
var json = [{
"city": "California",
"name": "Joe",
"age": 17
}, {
"city": "California",
"name": "Bob",
"age": 17
}, {
"city": "California",
"name": "Bob",
"age": 35
}, {
"city": "Texas",
"name": "Bob",
"age": 35
}, {
"city": "Florida",
"name": "Bob",
"age": 35
}
];
var hash = {}; // will be used for lookup of index of city in updated_json array.
var updated_json = [];
json.forEach(function(item,index){
// if city exists in hash then retrive its position from hash.
if(item.city in hash){
updated_json[hash[item.city]].count++;
}
else{
hash[item.city] = updated_json.length; // store position
updated_json.push({"name":item.city,"count":1});
}
});
console.log(updated_json);
You could collect the count with Map and render the result with the wanted properties.
var data = [{ city: "California", name: "Joe", age: 17 }, { city: "California", name: "Bob", age: 17 }, { city: "California", name: "Bob", age: 35 }, { city: "Texas", name: "Bob", age: 35 }, { city: "Florida", name: "Bob", age: 35 }],
result = Array.from(
data.reduce((m, { city }) => m.set(city, (m.get(city) || 0) + 1), new Map),
([name, count]) => ({ name, count })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here is how you will get it:
updatedJson = [
{
name: "California",
count: (_.filter(json, item => item.city === "California").length)
}
]