How to run nested React map function? - javascript

I have a JSON I need to fetch data & display in UI but not able to do due to nested.
JSON data:
data =[
{
"First Row": {
"info": 274.176,
}
},
{
"Second Row": {
"info": 139.536,
}
}
]
My Code:
{data
? data.map((val, i) =>
val[i].map((val2) => {
<>
<div>{val2.info}</div>
</>;
})
)
: ""}

Use Object.values() to get an array of all the values, then use [0] to get the first object where you can acces the info as desired:
data.map((val, i) => Object.values(val)[0].info)
[
274.176,
139.536
]
const data = [
{ "First Row": { "info": 274.176, } },
{ "Second Row": { "info": 139.536, } }
];
const r = data.map((val, i) => Object.values(val)[0].info);
console.log(r)

If you want to display only the info value, you can do the following. It loops through the data array. And for each item, gets the value of the first key. (assuming each item only has one key)
const DataDisplay = ({ data }) => {
return (
<div>
{data.map((item, index) => {
return (
<div key={index}>
<h3>{Object.keys(item)[0]}</h3>
<div>{Object.values(item)[0].info}</div>
</div>
);
})}
</div>
);
};

Related

How can i see my array on my component ? / React / Javascript

I have a element like :
const DropdownElements = [
{
key: 1,
title: "Şehir",
placeholder: "Şehir Seçiniz",
apiUrl: "https://api.npoint.io/995de746afde6410e3bd",
type: "city",
selecteditem: "",
data : [],
},
{
key: 2,
title: "İlçe",
placeholder: "İlçe Seçiniz",
apiUrl: "https://api.npoint.io/fc801dbd3fc23c2c1679", // its my apis. They hold datas from json
type: "district",
selecteditem: "",
data : [],
},
]
I fetching that url in App in useEffect.
const App = () => {
useEffect(() => {
DropdownElements.map((x) => {
fetch(x.apiUrl)
.then((z) => z.json())
.then((vb) => {
x.data=vb // If i write x.data.push(vb) i can see it on my component but its not giving pure array.
console.log(x.data) // I can see my datas perfectly. I trying fill my data.
});
});
}, []);
And i setting it like that :
<Space>
{DropdownElements.map((x) => {
return (
<PickerCompanent
showSearch
selecteditem={idhold}
key={x.key}
placeholder={x.placeholder}
type={x.type}
datasource={x.data} // I gave my datasource x.data that i filled .
onFocus={onFocus}
onChange={z=>onChange(z)}
onFocus={onFocus}
onSearch={onSearch}
></PickerCompanent>
);
})}
</Space>
But in my component when i try write like console.log(props) my datasource is empty array. How can i see my datas on my component ? I need set my array to a state in my component.
It seems like you aren't using any kind of state in your code.
const App = () => {
const [myData, setMyData] = useState();
useEffect(() => {
DropdownElements.map((x) => {
fetch(x.apiUrl)
.then((z) => z.json())
.then((vb) => {
x.data=vb // If i write x.data.push(vb) i can see it on my component but its not giving pure array.
console.log(x.data) // I can see my datas perfectly. I trying fill my data.
// in here you'll want to be adding your data to some state
// e.g.
setMyData(x.data);
});
});
}, []);
Then within your component, use that state:
datasource={myData}
Your object is updating but not view. To achieve this you need have a component state, to which we can update and trigger return again to update view.
const App = () => {
const [myData, setMyData] = useState(DropdownElements);
useEffect(() => {
myData.map((x, i) => {
fetch(x.apiUrl)
.then((z) => z.json())
.then((result) => {
myData[i].data = result;
setMyData(myData);
});
});
}, []);
return (
<Space>
{myData.map((x) => {
return (
<PickerCompanent
showSearch
selecteditem={idhold}
key={x.key}
placeholder={x.placeholder}
type={x.type}
datasource={x.data} // I gave my datasource x.data that i filled .
onFocus={onFocus}
onChange={z=>onChange(z)}
onFocus={onFocus}
onSearch={onSearch}
></PickerCompanent>
);
})}
</Space>
);

How to make correct loop of JSON in React

I've got a problem with making a correct loop in React. I want to fetch data from JSON to don't repeat components. I tried to make two loops and then two maps, but everything was in bad order. The other problem is that "description" is also an array that's why I'm not able to deal with it
JSON:
{
"oswiecim": [
{
"header": "Oświęcim Zasole",
"description": [
"Rejon ulic św Maksymiliana Kolbego",
"i Stanisławy Leszczyńskiej"
]
},
{
"header": "Oświęcim Zasole",
"description": [
"Rejon ulic Więźniów Oświęcimia",
"Obozowej, Polnej i Legionów"
]
},
{
"header": "Stare Miasto",
"description": [
"Rejon Rynku i Placu ks. Jana Skarbka oraz ",
"ulic Zamkowej i Władysława Jagiełły"
]
},
{
"header": "Stare Miasto",
"description": [
"Cmentarz Parafialny oraz rejon",
"ul. Wysokie Brzegi."
]
},
{
"header": "Osiedle Chemików",
"description": [
"Największa pod względem liczby ludności",
"dzielnica Oświęcimia"
]
}
]
}
React:
import '../../styles/selection/Selection.scss'
import { useEffect, useState } from 'react';
const Selection = () => {
const [data, setData] = useState({})
const getData = async () => {
await fetch('https://jsoneditoronline.org/#left=cloud.b95a27020e1c45e9b3a7c95a74fc5d49', {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then(res => res.json())
.then(data => {
setData(data)
})
}
useEffect(() => {
getData()
}, [])
const headers = []
const descriptions = []
for (const item of data.oswiecim) {
headers.push(item.header)
descriptions.push(item.description)
}
return (
<div className="selection">
{headers.map(item => (
<h1>{item}</h1>
))}
{descriptions.map(item => (
item.map(elem => (
<p>{elem}</p>
))
))}
</div>
);
}
export default Selection;
The result should look like this:
You don't need to separate header and description in two different variables.
So try something like this:-
return (
<div className="selection">
{data.oswiecim?.map((item) => (
<>
<h1>{item.header}</h1>
{item.description?.map((description) => (
<p>{description}</p>
))}
</>
))}
</div>
);
Live demo
Replace the setData(data); with following. It will just give the array you need to iterate,
setData(data.oswiecim);
Remove the following code,
const headers = []
const descriptions = []
for (const item of data.oswiecim) {
headers.push(item.header)
descriptions.push(item.description)
}
Replace return statement with following,
<div className="selection">
{data &&
data.map(item => (
<>
<div>{item.header}</div>
{item.description &&
item.description.map(descriptionItem => <p>{descriptionItem}</p>)}
</>
))}
</div>

What if there is no opportunity to create unique keys?

I have a complex data set, so I will show a very simplified version for an example.
Input data:
const data = [
{
type: "input",
caption: "Name",
defaultValue: "John Smith"
},
{
type: "input",
caption: "Name",
defaultValue: "John Smith"
},
{
type: "input",
caption: "Name",
defaultValue: "John Smith"
},
{
type: "input",
caption: "Name",
defaultValue: "John Smith"
},
{
type: "input",
caption: "Name",
defaultValue: "John Smith"
}
];
Each item of the array is removable. It turns out something like this.
There are several conditions. I should not modify the data array so i create a deep copy. As well inside the copy i can only delete elements but don't modify their properties. Thus each element has to have local state with a new value.
Working example:
function App() {
const [mainData, setMainData] = useState(deepCopy(data));
return (
<React.Fragment>
{
mainData.map((item, i) => {
return (
<Input {...item} key={i} num={i} setMainData={setMainData}/>
)
})
}
</React.Fragment>
)
}
const Input = (props) => {
const [value, setValue] = useState(props.defaultValue);
const deleteElem = () => {
props.setMainData((mainData) => {
return [...mainData.filter((_, ind) => ind !== props.num)];
});
};
return (
<div>
<div>
<div>{`${props.caption}:`}</div>
<input value={value} onChange={(e)=>setValue(e.target.value)}/>
</div>
<button onClick={deleteElem}>delete</button>
</div>
)
};
const deepCopy = (aObject) => {
if (!aObject) {
return aObject;
}
let value;
let bObject = Array.isArray(aObject) ? [] : {};
for (const key in aObject) {
value = aObject[key];
bObject[key] = (typeof value === "object") ? deepCopy(value) : value;
}
return bObject;
};
If you try to delete not the last element then (because of the keys) the values of the inputs elements will be mixed up.
What can I do about it?
With deepCopy you can add a unique id to each item when you initialize your state. Once you do that you can leverage that id for passing as key to the Input element
import {uuid} from 'uuidv4';
function deepCopyAndAddId = () => {
let newData = deepCopy(data);
newData = newData.map((item, index) => ({...item, id: uuid()}));
}
function App() {
const [mainData, setMainData] = useState(deepCopyAndAddId);
return (
<React.Fragment>
{
mainData.map((item, i) => {
return (
<Input {...item} key={item.id} num={i} setMainData={setMainData}/>
)
})
}
</React.Fragment>
)
}
To make minimum changes in your code - just never delete the item in deleteElem, but add a flag deleted to it instead.
When render an item, show <Fragment> for the deleted item.

Array.find returns TypeError / right use of params

I want to access name from the data array but keep getting 'TypeError: Cannot read property 'name' of undefined'. Can someone spot the mistake? <button>{itemName}</button> displays the name, but I can't access it with props...
export default function Home({ match }) {
const item = data.find(item => item.name === match.params.itemName);
return (
<div>
<button>{item.name.toUpperCase()}</button>
</div>
);
}
export const data = [
{
name: "Apple",
id: 1
},
{
name: "Banana",
id: 2
},
{
name: "Blueberry",
id: 3
}
];
You're just going to want to handle cases where there is no match or possibly invalid data.
export default function Home({ match }) {
const item = data
.filter(item => item && item.name) // only items that have a name
.find(item => item.name === match.params.itemName);
return item ? (
<div>
<button>{item.name.toUpperCase()}</button>
</div>
) : (
<div>
Item not found.
</div>
);
}

How to render a table with blueprintjs/table

I'm attempting to display a json array of data within a blueprintjs table. The table should be dynamic in it's rendering (number of rows and columns), so to display whatever is in the json array. In production, the json array will come from an API call, but to start off with, I'm just trying to get it working on some dummy data.
I've managed to generate the table dynamically and display the column headers, however I'm stuck on generating the actual data cells.
Here's my code so far:
interface ResultsTableProps {}
interface ResultsTableState {
numResultsRows? : number,
results
}
export default class ResultsTable extends React.Component
<ResultsTableProps, ResultsTableState> {
public state: ResultsTableState = {
numResultsRows: 0,
results: null
}
componentDidMount() {
var searchString = store.getState().submitSearch.searchString;
// Pretend an API call just happened and the results object is returned
// This is the dummy data
var resultsObject = getData();
this.setState({
numResultsRows: resultsObject.length,
results: resultsObject
});
}
private createColumn(columnData) {
return <Column name={columnData} />
}
private createColumns(columnDatas) {
return Object.keys(columnDatas[0]["_source"]).map(this.createColumn);
}
private createTable(results, numResultsRows) {
return (
<Table numRows={numResultsRows}>
{this.createColumns(results)}
</Table>
);
}
render() {
return (
<div id="results-table">
<Card interactive={false} elevation={Elevation.TWO} className={"pt-dark"}>
{this.createTable(this.state.results, this.state.numResultsRows)}
</Card>
</div>
);
}
}
When this code runs, I get a table, with the correct number of rows and the correct number of columns, and also with correct column headers.
I now need to somehow fill in the rows with the cells/data, and I'm stuck. I'm not sure how I should go about this.
How can it be done?
In case you'd like to see the dummy data:
[
{
"_type": "location",
"_id": "5sXFcmEBsayGTsLx1BqB",
"_source": {
"elevation": "",
"country": "ZA",
"geonameid": "958386",
"timezone": "Africa/Johannesburg",
"latitude": "-27.17494",
"mod_date": "2014-10-01",
"dem": "968",
"admin1_fips": "08",
"population": "0",
"alternatenames": "",
"feature_class": "S",
"geohash": "k7pt6ubwx0n0",
"name": "Sahara",
"alt_cc": "",
"fulltext": "ZA 958386 Africa/Johannesburg -27.17494 2014-10-01 968 08 0 S Sahara DC8 Sahara FRM NC083 21.91872",
"admin2": "DC8",
"asciiname": "Sahara",
"feature_code": "FRM",
"admin3": "NC083",
"longitude": "21.91872",
"admin4": ""
}
}
]
Note I'm only interested in display the data in the _source key. So the names of my columns are "elevation", "country", "geonameid", etc. And the cell data should be the values of those keys. My real dummy data actually has about 20 of these objects in the array, but i've just shown one for brevity.
Here is a more complete example.
const data = [
{foo: {bar: "baz"}},
...
]
// allows access to a deep object property by name
const getNestedProp = (obj, path) => (
path.split('.').reduce((acc, part) => acc && acc[part], obj)
)
const objectCellRenderer = (key) => (rowIndex) => {
return <Cell>{getNestedProp(data[rowIndex], key)}</Cell>
When rendering the table, define your column cellRenderer like this:
<Column name="someColumn" cellRenderer={objectCellRenderer("foo.bar")}/>
Instead of only passing they key, may pass key and value:
private createColumns(columnDatas) {
return Object.entries(columnDatas[0]["_source"]).map(this.createColumn);
}
Now you can get it like this:
private createColumn([key, value]) {
//...
}
You are just missing cellRenderer prop.
const createCell = (columnData) => (rowIndex) => {
return (
<Cell key={""}>{data[rowIndex][columnData]}</Cell>
);
};
Complete code =>
const SomeTable = () => {
const [data, setData] = useState("");
const [numDataRows, setNumDataRows] = useState(0);
useEffect(() => {
return
let fetchedData = []
// here you fetch data from somewhere
...
setData(fetchedData);
setNumDataRows(fetchedData.length);
});
}, []);
const createCell = (columnData) => (rowIndex) => {
return (
<Cell key={rowIndex + columnData}>{data[rowIndex][columnData]}</Cell>
);
};
const createColumn = (columnData, colIndex) => {
return (
<Column
name={columnData}
key={colIndex}
cellRenderer={createCell(columnnData)}
/>
);
};
const createColumns = (columnsData) => {
return columnsData ? Object.keys(columnsData[0]).map(createColumn) : [];
};
const CreateTable = (data, numDataRows) => {
return (
<Table numRows={numPlayersRows}>
{createColumns(data)}
</Table>
);
};
return <>{CreateTable(data, numDataRows)}</>;
};
export default SomeTable;

Categories

Resources