React material-ui, grid list cannot render grid items - reactjs

export interface FlatsGridProps {
flats: IClusterFlats[];
}
export const FlatsGrid: React.StatelessComponent<FlatsGridProps> = (props: FlatsGridProps) => {
if (props.flats.length === 0) {
return (<div> empty </div>);
}
return (
<div style={styles.root}>
<GridList
cols={2}
style={styles.gridList}
cellHeight={180}>
{props.flats.map((f, i) => {
<div key={i}> element </div>
})}
</GridList>
</div>
)
};
When I render GridList control it throws exception
Cannot read property 'props' of null in GridList.js
View from console below.

I think you need to return the child from the map. The grid.js complains about its child being undefined.
<GridList
cols={2}
style={styles.gridList}
cellHeight={180}>
{props.flats.map((f, i) => {
return (<div key={i}> element </div>)
})}
</GridList>

Related

Component is not being returned in nested loop

I am trying to render the child component inside a nested loop. However it is not being render in the second loop(red tick). Although it is rendered normally in the first loop (blue tick). Kindly highlight why is it no rendered in the second loop.
https://i.stack.imgur.com/LFiKU.png
Codesandbox Link : https://codesandbox.io/s/competent-nova-u9rzuh?file=/src/parent.js
import React from "react";
import ProductFeaturesCards from "./ProductFeaturesCards.js";
import { Products } from "../ProductsData.js";
const ProductFeatures = ({ className = "", id }) => {
return (
<section id='product-features' className={`${className}`}>
<div className='container'>
<div className='row d-flex justify-content-center'>
<div className='col-lg-12 col-md-12 col-sm-12 col-12 py70'>
<p className='features-title'>Product Features</p>
</div>
</div>
<div className='row'>
{Products.forEach((item, i) => {
if (item.id === id) {
// return <ProductFeaturesCards data={item} key={i} />;
Object.values(item.Product_features[0]).map((feature, index) => {
console.log("ProductFeaturesCards:", feature);
return <ProductFeaturesCards data={feature} key={index} />;
});
}
})}
</div>
</div>
</section>
);
};
export default ProductFeatures;
Can you try this. Not sure if this will work
if (item.id === id) {
// return <ProductFeaturesCards data={item} key={i} />;
return Object.values(item.Product_features[0]).map((feature, index) => {
console.log("ProductFeaturesCards:", feature);
return <ProductFeaturesCards data={feature} key={index} />;
});
}
The first mistake you did was using forEach. forEach will mutate the data and will not return anything. So, Instead you need to use map which doesn't mutate and returns the result.
The 2nd mistake is the return statement not added inside the if condition for the map. So, it never gets returned and hence your first map will not receive the value.
After this you should be able to run it.
<div className="row">
{Products.map((item) => { // replaced forEach with map
if (item.id === id) {
return Object.values(item.Product_features[0]).map( // return added
(feature, index) => {
return <Card data={feature} key={index} />;
}
);
}
})}
</div>

How to create a nested accordion in reactjs

Intro -
I'm trying to show JSON data in a Accordion. So I used react-sanfona (github) to build that. I'm trying to call getComponent function recursively so that I can check if it is an array or object if it is array I'm calling same function. better show you the pogress so far.
Problem - I'm getting [object Object] at the second level even I call the getComponent recursively
Edit on codesandbox
Problem was that you didn't return anything when dealing with object
So this part
Object.keys(record).map((key, index) => {
console.log(44);
return (
<AccordionItem className="ml-5" title={`1 - ${index}`} expanded>
{getComponent(record[key])}
</AccordionItem>
);
});
should be
return Object.keys(record).map((key, index) => {
console.log(44);
return (
<AccordionItem className="ml-5" title={`1 - ${index}`} expanded>
{getComponent(record[key])}
</AccordionItem>
);
});
I added a default expanded property and now it displays all data.
Check
this sandbox
Hy, I don't know exactly what you want to display but here is a version working.
import { Accordion, AccordionItem } from "react-sanfona";
import "./styles.css";
const datalist = [
{
id: 3423235234,
name: "John",
address: [
{
first: "city1",
second: "city2"
}
]
}
];
export default function App() {
function getComponent(record) {
if (Array.isArray(record)) {
return record.map((b, index) => (
<AccordionItem className="ml-5" title={`${index}`} key={index}>
{getComponent(b)}
</AccordionItem>
));
}
if (typeof record === "object") {
return (
<div>
{Object.keys(record).map((key, index) => {
return (
<AccordionItem
className="ml-5"
title={`1 - ${index}`}
expanded
key={index}
>
{getComponent(record[key])}
</AccordionItem>
);
})}
</div>
);
}
if (typeof record === "string" || typeof record === "number") {
console.log("string or number: ", record);
return <AccordionItem className="ml-5" title={`2 - ${record}`} />;
}
return (
<AccordionItem className="ml-5" title={`3 - ${record.toString()}`} />
);
}
return (
<div className="App">
<div className="px-7">
<Accordion>{getComponent(datalist)}</Accordion>
</div>
</div>
);
}
The package you're using raise many errors in the console (with no configuration). Did you check the material ui's accordions ? https://material-ui.com/components/accordion/
This is working code, which might help you
Here, initially root folder will be hiding all children once click on root -> its direct children will be displayed/hidden and so on
//explorer is the json coming from parent component
import React, { useState } from "react";
function Accodian({ explorer }) {
const [expand, setExpand] = useState(false);
if (explorer.children) {
return (
<div>
{/* {explorer.children ? ( */}
<>
<div onClick={() => setExpand((prevState) => !prevState)}>
{explorer.name}
</div>
{expand ? (
<>
{explorer.children.map((child) => {
// return <div key={child.name} style = {{paddingLeft: '20px'}}>{child.name}</div>;
return <Accodian explorer={child} key={child.name} />;
})}
</>
) : null}
</>
{/* ) : null} */}
</div>
);
} else {
return <div style={{ paddingLeft: "20px" }}>{explorer.name}</div>;
}
}
export default Accodian;
Check this sandbox : https://codesandbox.io/s/js-recursion-accordian-v03y5q?file=/src/components/Accordian.js:0-823/

How can I get elements from one component in another one by id or value?

I've created a component to create follow and unfollow buttons and now I want to use this component in other components (like Suggestions).
In the suggestions component I want to show only the button that its value is equal to the user.id, but I am only able to get the 5 buttons from the original component.
Is there a way to select only the button that is equal to the user.id?
This is the component that creates the buttons:
render() {
const { users, followingUsers } = this.state
const userId = this.props.user[0].id
return(
<div>
{users.map((user, index) => {
if(userId !== user.id) {
if(followingUsers.includes(user.user_name)) {
return(
<Button key={index} value={user.id} onClick={this.onUnfollow}>Unfollow</Button>
)
} else {
return(
<Button key={index} value={user.id} onClick={this.onFollow}>Follow</Button>
)
}
}
})}
</div>
)
}
}
export default withUser(Unfollowfollow);
Here is the suggestions component:
render() {
const { users } = this.state
const userId = this.props.user[0].id
return (
<div>
<ul>
{users.map((user, index) => {
if(user.id !== userId) {
return (
<Card className="users" key= {index}>
<CardBody>
<CardImg className="picfollowers" top width="9%" src={user.image} />
<CardTitle onClick={() => this.handleClick(user.id)}>{user.user_name}</CardTitle>
<Unfollowfollow />
</CardBody>
</Card>
)}
})}
</ul>
</div>
)
}
}
export default withUser(Suggestions);

TypeError: this.state.schedulelistnew.map is not a function

Create class 'ScheduleList' and initalize array elements
class ScheduleList extends Component {
state = {
schedulelistnew: []
};
Used to populate array elements from API using axios
componentDidMount() {
axios.get(`https://apiv2.apifootball.com/?action=get_H2H&firstTeam=Chelsea&secondTeam=Arsenal&APIkey=******`)
.then(res => {
const schedulelistnew = res.data;
this.setState({ schedulelistnew });
});
}
Render the array elements to the Component 'ScheduleListItem '
render() {
return (
<div>
<Row>
<Col lg="9" md="8">
{this.state.schedulelistnew.map(item => (
<div className="strong textmb-3 pb-2" key={item.match_id}>
<ScheduleListItem item={item} />
</div>
))}
What am I missing?
when the map process you forget about return
{this.state.schedulelistnew.map( item => {
return (
<div className="strong textmb-3 pb-2" key={item.match_id}>
<ScheduleListItem item={item} />
</div>
);
}
)}

Calling an External Function in a React Component

I have a need, in a site I'm building, for a list component that is reused several times. However, the list is purely for rendering and is not responsible for the state of the app at all. I know you either cannot, or are not supposed to have dumb components containing any logic, but I am not sure how to proceed without using a smart component, which is entirely unnecessary. Here is my smart component that works:
class Menu extends Component {
renderItems(items) {
return this.props.items.map((i, index) => {
return (
<li key={index} style={{marginLeft: 10}}>
{i}
</li>
)
});
}
render() {
const { listStyle } = styles;
return (
<div>
<ul style={listStyle}>
{this.renderItems()}
</ul>
</div>
)
}
}
And I've tried this:
function Menu(props) {
return props.items.map((i, index) => {
<li key={index} style={{marginLeft: 10}}>
{i}
</li>
});
}
And then calling it inside Nav like this, which does not throw an error but does not render anything from menu either:
const Nav = () => {
const { listStyle, containerStyle } = styles;
return (
<div style={containerStyle}>
<Logo url={'#'}
src={PickAPlayLogo}
width={300} />
<Menu items={pageLinks} />
<Menu items={socialMediaLinks} />
<Logo url={'#'}
src={AppStoreLogo}
width={170} />
</div>
);
};
Also, worth noting, I have never come across a function that is supposed to be rendered like a component, but was trying it based on the example on this page
Heres an answer similar to what you have going on
function Menu(props) {
this.renderItems = () => {
return (
<ul>
{props.items.map((i, index) => {
return (
<li>{i}</li>
)
})}
</ul
)
}
return(
this.renderItems()
)
}
Here we go:
function Menu(props) {
const {listStyle} = styles;
const listItems = props.items.map((i, index) =>
<li key={index} style={{marginLeft: 10}}>
{i}
</li>
);
return (
<ul style={listStyle}>{listItems}</ul>
);
}

Resources