I am passing props to a nested component. The props are coming in correctly but I am unable to pass them to a new array like so:
import React, {useState, useEffect} from 'react';
import {StyleSheet, View} from 'react-native'
import MapView, {Marker} from 'react-native-maps';
const Map = ({navigation, locationsOne, locationsTwo, locationsThree}) => { //these are coming in correctly when I console.log ie: {"coords":{"accuracy":602,"altitude":0,"heading":0,"latitude":99.4210083,"longitude":-100.0839934,"speed":0},"mocked":false,"timestamp":1572363100628}
const [markers, setMarkers] = useState([
{
location : locationsOne,
title: 'One'
},
{
location : locationsTwo,
title: 'Two'
},
{
location : locationsThree,
title: 'Three'
}
]);
return (
<MapView style={styles.map} initialRegion={currentLocation.coords}>
{markers.map((locationTEST) => (
console.log('location: ' + JSON.stringify(locationTEST)) //this returns nothing in the locations arrays ie: {"location":[],"title":"One"}
<MapView.Marker
title="This is a title"
description="This is a description"
coordinate={{
latitude: locationTEST.location.coords.latitude,
longitude: locationTEST.location.coords.longitude,
}}
/>
))}
</MapView>
);
the value of locationsOne looks like: {"coords":{"accuracy":602,"altitude":0,"heading":0,"latitude":99.4210083,"longitude":-100.0839934,"speed":0},"mocked":false,"timestamp":1572363100628}
How come I can't take the props and pass it into a new array (markers) array?
When <Map/> rendered at the first time, locationsOne still contain [].
When props (means locationsOne changed), state didn't changed.
So you should useEffect to update state when props changed.
const [markers, setMarkers] = useState ...
useEffect(() => {
const newMarkers = [
{
location : locationsOne,
title: 'One'
},
{
location : locationsTwo,
title: 'Two'
},
{
location : locationsThree,
title: 'Three'
}
];
setMarkers(newMarkers);
}, [locationsOne, locationsTwo, locationsThree]);
Rather then setting the useEffect callback array [] (this was bogging down the system as this re-runs the locations every time they change which was causing the locations to be called 1400 times), I just needed to setMarkers() like so:
useEffect(() => {
const newMarkers = [
{
location : locationsOne,
title: 'One'
},
{
location : locationsTwo,
title: 'Two'
},
{
location : locationsThree,
title: 'Three'
}
];
setMarkers(newMarkers);
}, []);
Related
Currently using a react in typescript.
make a separate file and manage it.
I want to do map work on the `card component
parameter on the map wrong?
definition wrong?
Can I get some advice...
Card.tsx
import { LIST_DATA, ListData } from './data';
const Card = () => {
return(
{LIST_DATA.map(({ id, title }: ListData[]) => {
return <S.InfoTitle key={id}>{title}</S.InfoTitle>;
})}
)
}
data.tsx
export interface ListData {
id: number;
title: string;
}
export const LIST_DATA: ListData[] = [
{
id: 0,
title: 'drawing',
},
{
id: 1,
title: 'total',
},
{
id: 2,
title: 'method',
},
{
id: 3,
title: 'material',
},
];
When you map, each item inside the map as argument is only one item from the original array. In your case you have an array of ListData but when you map each argument is only one of this ListData item type, therefore you have to change ListData[] to ListData as such:
import { LIST_DATA, ListData } from './data';
const Card = () => {
return(
{LIST_DATA.map(({ id, title }: ListData) => {
return <S.InfoTitle key={id}>{title}</S.InfoTitle>;
})}
)
}
Otherwise to answer the main question: map in typescript is the same as map in javascript, you just have to ensure you input the right type in order to "secure" your app.
I'm new to React and programing in general and I'm having trouble writing code that return each element in an array, in React JS.
the whole code is below:
import React from 'react'
const App = () => {
const course = {
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10
},
{
name: 'Using props to pass data',
exercises: 7
},
{
name: 'State of a component',
exercises: 14
}
]
}
const Header = (props) => {
return (
<h1>{props.course.name}</h1>
)
}
const Content = (props) => {
const lisItem = props.course.parts.map((part =>
<li>{props.course.parts.name}</li>
))
return (
<ul>{lisItem}</ul>
)
}
return (
<div>
<Header course={course}/>
<Content course={course}/>
</div>
)
}
export default App
Right now it half-works: I can display 3 bullet points (match with numbers of parts) but cannot display the name of the part itself.
Also I would like to clarify the out put a wanted is the course's name and each name of the parts be displayed.
Any help would be appreciated. Thank you very much.
You are not using map correctly. It should be like this:
const lisItem = props.course.parts.map((part) => <li>{part.name}</li>);
You were ignoring each part given to you by map. Check docs of map.
Also I see now you were defining the two components Header and Content inside the App component, that is not good practice (due to reconciliation), move their definition outside of App:
import React from "react";
const Header = (props) => {
return <h1>{props.course.name}</h1>;
};
const Content = (props) => {
const lisItem = props.course.parts.map((part) => <li>{part.name}</li>);
return <ul>{lisItem}</ul>;
};
const App = () => {
const course = {
name: "Half Stack application development",
parts: [
{
name: "Fundamentals of React",
exercises: 10,
},
{
name: "Using props to pass data",
exercises: 7,
},
{
name: "State of a component",
exercises: 14,
},
],
};
return (
<div>
<Header course={course} />
<Content course={course} />
</div>
);
};
Your .map( part => ...) iterates props.course.parts, the part inside the map function is a single item of the list.
Check MDN for more info https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
If i add the dependency array "fitems" in the dependecy array like its telling me to do, then it causes infinite loop. also if i dont use the spread operator on the array then the warning doesnt show but then the state change doesnt rerender.
Sidebar.tsx
import { useState, useEffect } from "react";
import { Link, useLocation } from "react-router-dom";
import axios from "axios";
import getItems from "./../services/SidebarItems";
import { sidebarInfoUrl } from "./../services/ApiLinks";
function Sidebar() {
const fItems = getItems();
const location = useLocation();
const paths = location.pathname.split("/");
const [items, setItems] = useState(fItems);
useEffect(() => {
axios.get(sidebarInfoUrl).then((response) => {
const updatedItems = [...fItems]
updatedItems.forEach((item) => {
if (item.match === "projects") item.value = response.data.projects;
else if (item.match === "contacts") item.value = response.data.contacts;
});
setItems(updatedItems);
console.log("here")
});
}, []);
return (
<div className="sidebar shadow">
{items &&
items.map((item) => (
<Link
key={item.match}
to={item.link}
className={
paths[2] === item.match ? "sidebar-item active" : "sidebar-item"
}
>
<span>
<i className={item.icon}></i> {item.title}
</span>
{item.value && <div className="pill">{item.value}</div>}
</Link>
))}
</div>
);
}
export default Sidebar;
Here is the sidebar items i am getting from getItems().
sidebarItems.ts
const items = () => {
return [
{
title: "Dashboard",
icon: "fas fa-home",
link: "/admin/dashboard",
match: "dashboard",
value: "",
},
{
title: "Main Page",
icon: "fas fa-star",
link: "/admin/main-page",
match: "main-page",
value: "",
},
{
title: "Projects",
icon: "fab fa-product-hunt",
link: "/admin/projects",
match: "projects",
value: "00",
},
{
title: "Contacts",
icon: "fas fa-envelope",
link: "/admin/contacts",
match: "contacts",
value: "00",
},
];
};
export default items;
Thank to AKX. I found my problem. I had to use useMemo Hook so that my getItem() function doesnt cause infinte loop when i add it to dependency array.
const fItems = useMemo(() => {
return getItems();
}, []);
instead of
const fItems = getItems();
Another fix is that,
If i dont send the items from SidebarItems.ts as function but as an array then it wont cause the infinte loop even if i dont use useMemo hook.
I have a material table and I use selection and filtering.
Above my material table I have a button that should "send" the selected rows to its parent if you click on it.
How can I retrieve the selected Rows though? I know I can do
const [selectedRows, setSelectedRows] = useState([]);
<MaterialTable
...
onSelectionChange={(rows) => {
setSelectedRows(rows);
}}
... />
But the setSelectedRows results in the Table to be rerendered and then all my filters are gone. I know I could store filters in a state too , but this sounds like way too much overhead for just the simpe question to retrieve the selectedRows at a certain point in time.
Any easy suggestions?
Thanks a lot for your help
Use the components prop and lift the FilterRow component into parent state like below. The filter values will persist.
import MaterialTable, { MTableFilterRow } from 'material-table';
const Parent = () => {
const [components, whatever] = useState({
FilterRow: props => <MTableFilterRow {...props} />,
});
const [columns] = useState([
{ title: "Name", field: "name" },
{ title: "Pet", field: "pet" }
]);
const [data] = useState([
{ name: "Jim", pet: "Dog" },
{ name: "Tom", pet: "Horse" },
{ name: "Susan", pet: "Rat" },
{ name: "Penny", pet: "Cat" }
]);
return (
<MaterialTable
columns={columns}
data={data}
components={components}
/>
);
}
``
Add a ref to the component
<MaterialTable
tableRef={tableRef}
you can get selected rows with
tableRef.current.dataManager.data.filter(o => o.tableData.checked)
I am working with Material-UI and getting data from the backend. There is no issue with the backend, but I don't know how to loop data and print it in a table format using Material-UI.
Can anyone guide me on how to print data in a table format?
Here is my code so far:
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { getProducts } from "../../services/products";
import MaterialTable, { MTableToolbar } from "material-table";
const productsList = props => {
const [data, setData] = useState([]);
const [state] = React.useState({
columns: [
{ title: "Brand", field: "brand" }, //assume here my backend schema is brand
{ title: "Price", field: "price" }, //here price
{ title: "Model no", field: "model" } //here model
]
});
const getProducts = async () => {
try {
const res = await getProducts();
setData(res.data);
console.log(res.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getProducts();
}, []);
return (
<MaterialTable
components={{
Toolbar: props => {
return (
<div>
<MTableToolbar {...props} />
</div>
);
}
}}
options={{
actionsColumnIndex: 5,
selection: true
}}
/>
);
};
export default function Company() {
return <productsList />;
}
You have to set the data and columns value. So try it like this:
import React, { useState, useEffect } from "react";
import MaterialTable, { MTableToolbar } from "material-table";
const fakeFetch = () => {
return new Promise(resolve => {
resolve({
data: [
{ brand: "brand 1", price: 1, model: "123" },
{ brand: "brand 2", price: 1, model: "456" },
{ brand: "brand 3", price: 1, model: "789" }
]
});
});
};
export default function App() {
const [data, setData] = useState([]);
// When the columns don't change you don't need to hold it in state
const columns = [
{ title: "Brand", field: "brand" }, //assume here my backend schema is brand
{ title: "Price", field: "price" }, //here price
{ title: "Model no", field: "model" } //here model
];
const getProducts = async () => {
try {
const res = await fakeFetch();
setData(res.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getProducts();
}, []);
return (
<MaterialTable
columns={columns} // <-- Set the columns on the table
data={data} // <-- Set the data on the table
components={{
Toolbar: props => {
return (
<div>
<MTableToolbar {...props} />
</div>
);
}
}}
options={{
actionsColumnIndex: 5,
selection: true
}}
/>
);
}
To make it even easier you could also provide your fetch function (fakeFetch in this case) as the data value;
data={fakeFetch} // <-- Using this you wouldn't need the [data, setData], getProducts and useEffect code.
Working sandbox link
As per the material-table approach, you have to put your whole fetched data on the data prop inside the MaterialTable component. So as far as I can understand, there is no looping made in this case by using the material-table library.
Assuming the attributes in your data object match the field names specified in your columns prop (if not, create an array of objects from your fetched data that matches the column fields or vice-versa).
And the code would be just the addition of the data prop in your table:
<MaterialTable
// ... existing props
data={data}
/>
Keep in mind that you could also use the remote data approach as described in the documentation which gives you the means to immediately query your data and fetch it inside the data prop of the table.