array map split join, javascript - javascript

I need help in understanding this piece of code.
What is it doing and what is the type its returning. Possibly break it in smaller chunks to understand.
Why would it join array elements on '.' and then split them using the same dilimentor'.' What type of array is being passed back from search results?
function getRandomInt(max, min = 0) {
return Math.floor(Math.random() * (max - min + 1)) + min; // eslint-disable-line no-mixed-operators
}
const searchResult = query =>
new Array(getRandomInt(5))
.join('.')
.split('.')
.map((item, idx) => {
const category = `${query}${idx}`;
return {
value: category,
label: (
<div
style={{
display: 'flex',
justifyContent: 'space-between',
}}
>
<span>
Found {query} on{' '}
<a
href={`https://s.taobao.com/search?q=${query}`}
target="_blank"
rel="noopener noreferrer"
>
{category}
</a>
</span>
<span>{getRandomInt(200, 100)} results</span>
</div>
),
};
});
its been called like this
const [options, setOptions] = useState<SelectProps<unknown>["options"]>([]);
const handleSearch = (value: string) => {
setOptions(value ? searchResult(value) : []);
};
I want to be able to put console.log to see what value is setOptions getting.
Thanks
----------------- Update 2-----------------
const searchResult = (query: string) => {
const myArray = new Array(getRandomInt(5)).fill(0).map((item, idx) => {
const category = `${query}${idx}`;
return {
value: category,
label: labelElement(query, category),
};
});
console.log(myArray);
return myArray;
};
const labelElement = (query: string, category: string) => {
return (
<div
style={{
display: "flex",
justifyContent: "space-between",
}}
>
<span>
Found {query} on <a>{category}</a>
</span>
<span>{getRandomInt(200, 100)} results</span>
</div>
);
};
const [options, setOptions] = useState<SelectProps<unknown>["options"]>([]);
const handleSearch = (value: string) => {
setOptions(value ? searchResult(value) : []);
};

If we translate what searchResult does in plain English, I think it will be something like this:
Generate & return an array of objects which length should be between 0 and 5 (including both values).
Objects in array should have this shape:
{
value: string,
label: JSX.Element
}
The trick with .join('.').split('.') seems to be needed to make array iterable with .map.
If you try to call new Array(5).map(() => 'I am ignored 😐') you will see that you'll get an empty array, and .map(...) part will be simply ignored.
That happens because new Array(5) returns an array of empty cells which are ignored by .map(...). A more usual way to deal with it would be something like this:
new Array(5).fill().map(() => 'Now it works!');

Related

This filter method is working in console but not in ui in react

I want to filter items by filter method and I did it but it doesn't work in UI but
when I log it inside console it's working properly
I don't know where is the problem I put 2 images
Explanation of this code:
Looping inside currencies_info by map method and show them when I click on it and this completely working then I want filter the list when user enter input inside it I use filter method and this completely working in console not in UI
import React, { useState } from "react";
// Artificial object about currencies information
let currencies_info = [
{
id: 1,
name: "بیت کوین (bitcoin)",
icon: "images/crypto-logos/bitcoin.png",
world_price: 39309.13,
website_price: "3000",
balance: 0,
in_tomans: 0
},
{
id: 2,
name: "اتریوم (ethereum)",
icon: "images/crypto-logos/ethereum.png",
world_price: 39309.13,
website_price: "90",
balance: 0,
in_tomans: 0
},
{
id: 3,
name: "تتر (tether)",
icon: "images/crypto-logos/tether.png",
world_price: 39309.13,
website_price: "5",
balance: 0,
in_tomans: 0
},
{
id: 4,
name: "دوج کوین (dogecoin)",
icon: "images/crypto-logos/dogecoin.png",
world_price: 39309.13,
website_price: "1000000",
balance: 0,
in_tomans: 0
},
{
id: 5,
name: "ریپل (ripple)",
icon: "images/crypto-logos/xrp.png",
world_price: 39309.13,
website_price: "1,108",
balance: 0,
in_tomans: 0
}
];
export default function Buy() {
// States
let [api_data, set_api_data] = useState(currencies_info);
const [currency_icon, set_currency_icon] = useState("");
const [currency_name, set_currency_name] = useState("");
const [currency_price, set_currency_price] = useState(0);
const [dropdown, set_drop_down] = useState(false);
let [search_filter, set_search_filter] = useState("");
// States functions
// this function just toggle dropdown list
const toggle_dropdown = () => {
dropdown ? set_drop_down(false) : set_drop_down(true);
};
// this function shows all currencies inside dropdown list and when click on each item replace
// the currency info and hide dropdown list
const fetch_currency = (e) => {
set_drop_down(false);
currencies_info.map((currency) => {
if (e.target.id == currency.id) {
set_currency_name(currency.name);
set_currency_icon(currency.icon);
set_currency_price(currency.website_price);
}
});
};
// this function filter items base on user input value
const filter_currency = (e) => {
set_search_filter = currencies_info.filter((currency) => {
return currency.name.indexOf(e.target.value) !== -1;
});
api_data = set_search_filter;
console.log(api_data);
};
return (
<div className="buy-page-input" onClick={toggle_dropdown}>
{/* currency logo */}
<div className="currency-logo">
<img src={currency_icon} width="30px" />
</div>
{/* currency name in persian */}
<span className="currency-name">{currency_name}</span>
{/* currency dropdown icon */}
<div className="currency-dropdown">
<img className={dropdown ? "toggle-drop-down-icon" : ""}
src="https://img.icons8.com/ios-glyphs/30/000000/chevron-up.png"
/>
</div>
</div>
{/* Drop down list */}
{dropdown ? (
<div className="drop-down-list-container">
{/* Search box */}
<div className="search-box-container">
<input type="search" name="search-bar" id="search-bar"
placeholder="جستجو بر اساس اسم..."
onChange={(e) => {
filter_currency(e);
}}/>
</div>
{api_data.map((currency) => {
return (<div className="drop-down-list" onClick={(e) => {
fetch_currency(e);}} id={currency.id}>
<div class="right-side" id={currency.id}>
<img src={currency.icon} width="20px" id={currency.id} />
<span id={currency.id}>{currency.name}</span>
</div>
<div className="left-side" id={currency.id}>
<span id={currency.id}>قیمت خرید</span>
<span className="buy-price" id={currency.id}>
{currency.website_price}تومان</span>
</div>
</div>);})}
</div>) : ("")});}
Your search_filter looks redundant to me.
Try to change the filter_currency function like this:
const filter_currency = (e) => {
const search = e.target.value;
const filtered = currencies_info.filter((currency) => {
return currency.name.includes(search);
});
set_api_data(filtered);
};
It looks like you are never setting the api_data after you set the filter state.
Change the following
api_data = set_search_filter
console.log(api_data)
to
api_data = set_search_filter
set_api_data(api_data)
However, it then looks like set_search_filter is never used and only set so to improve this further you could remove that state and just have it set the api_data direct. Something like this:
const filter_currency = (e) => {
const search_filter = currencies_info.filter((currency) => {
return currency.name.indexOf(e.target.value) !== -1
})
set_api_data(search_filter)
}
Change your state value from string to array of the search_filter like this -
let [search_filter, set_search_filter] = useState([]);
and also it should be like this -
const filter_currency = (e) => {
const filterValues = currencies_info.filter((currency) => {
return currency.name.indexOf(e.target.value) !== -1;
});
set_search_filter(filtervalues);
set_api_data(filterValues);
console.log(filterValues);
};
and use useEffect with search_filter as dependency, so that every time search_filter value is being set, useEffect will trigger re render, for eg:-
useEffect(()=>{
//every time search_filter value will change it will update the dom.
},[search_filter])

How do I sustain data from DB while using another GET request with different query string in React(Next.js)?

I don't speak English very well. Please be understanding!
First, please check my code!
export default function DriveFolder() {
const [clickFolderPk, setClickFolderPk] = useState(1);
const viewFolder = async () => {
const url = `/api/store/drive/view-folder?folderId=${clickFolderPk}`;
await get(url)
.then((res) => {
console.log(res);
setMainFolder(res.directChildrenFolders);
})
.catch((error) => {
console.log(error);
});
};
useEffect(() => {
viewFolder();
}, [clickFolderPk]);
return (
<div className={classes.driveFolder}>
{mainFolder.map((main, key) => (
<TreeView>
<TreeItem
onClick={() => setClickFolderPk(main.FOLDER_PK)}>
<TreeItem nodeId='10' label='OSS' />
<TreeItem nodeId='6' label='Material-UI'>
<TreeItem nodeId='7' label='src'>
<TreeItem nodeId='8' label='index.js' />
<TreeItem nodeId='9' label='tree-view.js' />
</TreeItem>
</TreeItem>
</TreeItem>
</TreeView>
))}
</div>
);
}
I edited some code to make it clear. (might misspelled)
With this code, on the first rendering, since 'clickFolderPk' value is 1, I get the right data from DB.
However, since I have subfolders within folders from 'clickFolderPk' value 1, I have to request another GET REQUEST to see my subfolders from root folders.
Here is the simple image that you can understand my situation better.
this is what I get from 'clickFolderPk' value 1.
However, when I press 'kikiki', GET request functions and render like this.
.
This is not the way I want to render things.
I want every data from DB, however they don't disappear whenever I use different GET request with different PK number.
I want them stay on the screen and get the subfolders within them.
I'm struggling with this issue for quite a time.
Your help will be really appreciated!!!!!
It's all about Nesting: Folders have sub-folders, etc and it goes on...
Note: To break things down, I will answer from a React point of view disregarding how your backend api is structured or returns data.
Basically there are two main approaches,
Approach #1:
The global state is a single source of truth for all the folders think of it like this:
const [allFolders, setAllFolders] = useState([
{
id: "1",
name: "a-1",
folders: [
{
name: "a-subfolder-1",
folders: [{ name: "a-subfolder-subfolder-1" }],
},
{ name: "subfolder-2" },
],
},
]);
The problem is that any small update requires to mutate the entire state. So I will focus more on Approach #2
Approach #2:
There is the main tree that has child components, child components can expand and have children too:
import { useEffect, useState } from "react";
import "./styles.css";
export default function DriveFolder() {
const [folders, setFolders] = useState([
{ id: "1", name: "folder-a" },
{ id: "2", name: "folder-b" },
{ id: "3", name: "folder-c" }
]);
return (
<div style={{ display: "flex", flexDirection: "column" }}>
{folders.map((folder) => {
return <Folder key={folder.id} folder={folder} />;
})}
</div>
);
}
const Folder = ({ parent = undefined, folder }) => {
const [subfolders, setSubfolders] = useState([]);
const [isOpened, setOpened] = useState(false);
const hasSubfolders = subfolders.length > 0;
useEffect(() => {
// send request to your backend to fetch sub-folders
// --------------- to ease stuff I will hard code it
// with this you can limit the example of nest you wish
const maxNestsCount = 5;
const subfolderParent = parent || folder;
const subfolder = {
id: subfolderParent.id + "-sub",
name: "subfolder-of-" + subfolderParent.name
};
const currentNestCount = subfolder.name.split("-sub").length;
setSubfolders(currentNestCount < maxNestsCount ? [subfolder] : []);
// -----------------------------
}, []);
const handleToggleShowSubFolders = (e) => {
e.stopPropagation();
if (!hasSubfolders) {
return;
}
setOpened(!isOpened);
};
return (
<div
style={{
display: "flex",
flexDirection: "column",
paddingHorizontal: 5,
marginTop: 10,
marginLeft: parent ? 20 : 0,
backgroundColor: "#1678F230",
cursor: hasSubfolders ? "pointer" : undefined
}}
onClick={handleToggleShowSubFolders}
>
{folder.name}
<div style={{ display: isOpened ? "block" : "none" }}>
{subfolders.map((subfolder) => (
<Folder key={subfolder.id} parent={folder} folder={subfolder} />
))}
</div>
</div>
);
};
Try it out:
Here is the output of the sample code above:

How to get value from array outside of loop

How can I get the value of oneHundredColorLevel from the array and render it outside the container of the other colors? Each set of colors should be the boxes for each color, with a separate box for the 100 level color.
Link to codepen
const colorPalette = {
Dark10: "#FEF9E8",
Dark20: "#FDF4DE",
Dark30: "#FCEFCC",
Dark40: "#F7E0A2",
Dark50: "#F0CC72",
Dark60: "#D5B363",
Dark70: "#C7A55E",
Dark80: "#B39553",
Dark90: "#9D8240",
Dark100: "#89723E",
Dark110: "#7C6737",
Dark120: "#715E32",
Dark130: "#66552E",
Dark140: "#5B4A28"
};
const ColorSwatches = ({ colors, shade }) => {
let filtered = Object.fromEntries(
Object.entries(colors).filter(([key, value]) => key.includes(shade))
);
let onehundredcolor = [];
return (
<div class="wrapper">
<div class="bigNumber">
<h1>{onehundredcolor}</h1><----SHOULD BE NAME ONLY
<p>{onehundredcolor}</p><----SHOULD BE HEX VALUE ONLY
</div>
{Object.entries(filtered).map((color, i) => {
if (i === 9) {
onehundredcolor.push(color);
console.log(onehundredcolor)
}else if(i !== 9) {
return (
<div key={i} style={{ backgroundColor: `${color[1]}` }}>
<h2>{color[0]}</h2>
<p>HEX {color[1]}</p>
</div>
);
}
})
</div>
);
};
I think that an array would be a more flexible container here than an object whose properties are the various shade/color pairs. For example:
const colors = [
{shade: 'dark', color: '#FEF9E8'},
{shade: 'dark', color: '#FDF4DE'},
...
{shade: 'light', color: '#111111'},
{shade: 'light', color: '#111122'},
...
];
Then you can filter/map as you see fit, for example:
const darkColors = colors.filter(c => c.shade === 'dark');
const lightColors = colors.filter(c => c.shade === 'light');
And you can easily access the 10th dark color via:
darkColors[9]

React: How to bold words in an array of strings based on keyword

Let's say I have an array of values that I need to filter through and return all values based on a keyword search and return 3 results.
var fruits = ["Banana", "Orange", "Apple", "Mango", "Peach"];
array = array.filter(item => {
return item.toLowerCase().indexOf(term) > -1;
}).slice(0, 3)
What I am having trouble doing is bolding the term searched for each item. For instance, if i searched "a", I should return an array of jsx code where each time the "a" is listed in the results, it is bold:
[
<span>B<strong>a</strong>n<strong>a</strong>n<strong>a</strong></span>,
<span>Or<strong>a</strong>nge</span>,
<span><strong>A</strong>pple</span>
]
I have tried something to the effect of:
array = array.map((item, index) => (
<span>
{item.split('a')} // then somehow join the a back with the strong tags
</span>
));
also tried something like this, but the returned value is in string format and cannot to my knowledge converted to jsx:
array.map(item => {
return item.replace(new RegExp('(' + term + ')', 'ig'), '<strong>$1</strong>');
});
Any help is much appreciated.
You are pretty close, you need to check if the element of the array has the search term then also split the element into letters to match for that term (https://stackblitz.com/edit/react-earc4c)
import React from 'react';
export default function App() {
var fruits = ['Banana', 'Orange', 'Apple', 'Mango', 'Peach', 'Blueberry'];
return (
<div style={{ backgroundColor: 'palegoldenrod' }}>
{fruits.map(fruit => {
if (/a/.test(fruit)) {
return (
<p>
{fruit.split('').map(letter => {
if (letter === 'a') {
return <strong>{letter}</strong>;
}
return letter;
})}
</p>
);
}
return fruit;
})}
</div>
);
}
#hunter-mcmillen pointed me in the right direction, which led me to the solution, all credit goes to him!!! I may have misrepresented my problem a little... I needed to bold the word if it had the letter "a" in it. Below is what i was looking for, Thanks again Hunter!!!
import React from 'react';
export default function App() {
var fruits = ['Banana', 'Orange', 'Apple', 'Mango', 'Peach', 'Blueberry'];
return (
<div style={{ backgroundColor: 'palegoldenrod' }}>
{fruits.map(fruit => {
if (/a/.test(fruit)) {
return (
<p>
{fruit.split(' ').map(word => {
if (word.indexOf('a') != -1) {
return <strong>{word}</strong>;
}
return word;
})}
</p>
);
}
return fruit;
})}
</div>
);
}
I also want to mention a friend of mine solved this a different way:
let term = 'apple orange banana';
let search = 'a';
let parts = term.split(search);
return parts.map((item, i) => (
<>{item && <strong>{item}</strong>}{(i !== parts.length - 1) ? search : null}</>
))

Array.map / Filter a contigous array and then re-order it to be contiguous again

Using React, I have a list component that uses array.map to render a list of items.
The list items are variegated; every other list item has a different background color which depends on if the id field of the data structure that feeds the list item is even or odd:
...
const useStyles = makeStyles((theme) => ({
even: {
backgroundColor: theme.palette.background.paper,
},
odd: {
backgroundColor: "#c8c9c7",
},
}));
...
const classes = useStyles();
...
{!list || list.length < 1 ? (
<p>You have no assets selected...</p>
) : (
list.map((items) => (
<ListItem
className={items.id % 2 === 0 ? classes.even : classes.odd}
key={items.id}
>
...
/>
</ListItem>
))
)}
Here is an example of the data structure it uses:
{
{
"id":0,
"foo":"This is a bar"
},
{
"id":1,
"foo":"This is also a bar"
},
{
"id":2,
"foo":"Yes, this too, is a bar"
}
}
I need to remove items. Normal javascript.filter produces non contiguous ids as expected:
{
{
"id":0,
"foo":"This is a bar"
},
{
"id":2,
"foo":"Yes, this too, is a bar"
}
}
I need them to be contiguous:
{
{
"id":0,
"foo":"This is a bar"
},
{
"id":1,
"foo":"Yes, this too, is a bar"
}
}
I have a function that does what I need that needs some tweaking:
const handleRemoveAsset = (id) => {
const arrayCopy = [...assetListItems];
const filteredArray = arrayCopy
.filter((item) => item.id !== id)
for (var i=0; i < filteredArray.length; i++) {
filteredArray[i].id = i;
}
setAssetListItems(filteredArray);
};
This works, but one does not simply for loop using React... I am hoping to use filter and/or map for the entirety of this and not use the for loop that I have.
I read that you can chain filter and map and tried it but couldn't quite work it out. I came up with this:
const filteredArray = array
.filter((item) => item.id !== id)
.map((item, index) => {
item && item.id ? item.id : index)});
... which fails to compile with - expected an assignment to a function call and instead saw an expression on the line after .map.
Any advice at this point would appreciated, thank you!
You could chain map and filter and return the new object from map which updates the pre-existing id.
[...assetListItems]
.filter(item => item.id !== id)
.map((item, index) => ({
...item,
id: index,
}));
I just considered another scenario where if the id is not starting with 0. And if you want the starting id in the resultant array to be as the id of the first object then this is just another way of achieving the expected output.
let data = [{id:0, foo:'This is a bar'},{id:1, foo:'This is also a bar'},{id:2, foo:'Yes, this too, is a bar'}];
const filterItems = (items, id) => {
let lastPushedId = items[0]?.id;
return items.filter(item => item.id !== id).map(item => ({
...item,
id: lastPushedId++
}))
}
console.log(filterItems(data, 1));
//`id` of the first object is `3`
data = [{id:3, foo:'This is a bar'},{id:4, foo:'This is also a bar'},{id:5, foo:'Yes, this too, is a bar'}];
console.log(filterItems(data, 3));
.as-console-wrapper {
max-height: 100% !important;
}

Categories