Nice way in React to Map an array data to Card Decks - javascript

I have an array of objects. And I can't figure out how do I create multiple card decks with 3 cards in each one, as on the image:
An example is below:
import { Card, Button, ... CardBlock } from 'reactstrap';
export default const Example = (props) => {
return (<div>
<CardDeck>
<Card>
<CardImg top width="100%" src="https://..." />
<CardBlock>
<CardTitle>{data.title}</CardTitle>
<CardSubtitle>{data.subtitle}/CardSubtitle>
<CardText>{data.text}</CardText>
<Button>Button</Button>
</CardBlock>
</Card>
<Card>
...
</Card>
<Card>
...
</Card>
</CardDeck>
<CardDeck>
...
</CardDeck>
...
</div>
);
};

If your question is about how to iterate over your array then you can use Array.prototype.map() for it.
An example from the react docs with map() call using an arrow function:
By saving the components in a temporary variable:
function NumberList(props) {
const numbers = props.numbers;
const listItems = numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
);
return (
<ul>
{listItems}
</ul>
);
}
By using map() inline:
function NumberList(props) {
const numbers = props.numbers;
return (
<ul>
{numbers.map((number) =>
<ListItem key={number.toString()}
value={number} />
)}
</ul>
);
}
EDIT:
Do not render multiple <CardDeck> components. Instead adapt your css so that a <Card> will wrap into the next row when there are more that three. Then you only have to map the data inside your array once and not for every <CardDeck> again.

Related

Each child in a list should have a unique "key" prop. I made it, but still see this error

I know about key prop, so i made it in listitem component
const ListItem = ({item}) => {
const {result, time, id} = item;
return(
<li key={id} className='list__item'>
<span className='item__result'>{result} cps</span>
<span className='item__date'>{time}</span>
<button className='item__delete'>delete</button>
</li>
)}
And here is component, where I use it
const Leadboard = () => {
const [data, setData] = useState([{result:'5,63', time:'08.06.2022', id: (new Date()).toString(16)}, {result:'5,63', time:'08.06.2022', id: +(new Date() - 1)}, {result:'5,63', time:'08.06.2022', id: +(new Date() - 2)}]);
let elements=data.map(item => {
return (
<>
<ListItem item={item} />
</>
)
});
return(
<div className='app-leadboard'>
<span className='app-leadboard__title'>Your's best results:</span>
<ol className='app-leadboard__list' type='1'>
{elements}
</ol>
</div>
)}
But after render I still see "key prop" error
I spent so much time on this, but can't understand what's wrong. So smb, help pls with it
You’ve got the wrong list. It’s the <ListItem> components that need the key. (And you can get rid of the react fragments around them because they are pointless).
React first accesses the empty bracket (<> </> ) before accessing the key attribute in your child component.
So you need to either
Make use of the empty brackets and pass the key attribute to it
// Use React.Fragment
let elements=data.map(item => { return
(
<React.Fragment key={item.id}>
<ListItem item={item} />
</React.Fragment>
)
});
and remove the key in the child (ListItem) component
ListItem.js
<li
/* Remove this
key={id}
*/
className='list__item'>
OR
Get rid of the empty brackets (<> </>) and reference the child's component directly.
let elements=data.map(item => {
return (<ListItem item={item} />)
});
and leave the key attribute in the child component
More on React Fragment. React Official Docs

How to render a JSX component for each item in array

I need to render one jsx component for each item in an array.
import { ListView } from './components'; // Custom component
const array = ["item1","item2","item3"];
export default function App() {
return(
<div>
{/* Here i want to render a <ListView /> component for each of the items in the array. */}
</div>
);
}
Here there are 3 items in the array so i want to render 3 different components.
Any help will be appreciated.
Try to use map method:
return (
<div>{ array.map(item => <ListView key={item} item={item} /> }</div>
)

HTML elements not rendering on Gatsby website

What I am doing:
Creating my first website in Gatsby.js. Trying to render an HTML element "onClick" of a navigation link. When someone clicks one of the links, I want it to show a dropdown menu.
export function DropDownMenu(props) {
return (
<p>{props}</p>
)
}
const Header = () => {
// const [open, setOpen] = useState(false);
return (
<Nav>
<StyledLinkBox to="/"><Logo/></StyledLinkBox>
<Bars />
<NavMenu>
{headerMenuData.map((item, index, dropdown) => (
<NavLink to={item.link} key={index} onClick={() => {
item.dropdown.map((item, index) => (
<DropDownMenu props={item} key={index}/>
))}
}>
{item.title}
</NavLink>
))}
<StyledButton>Early Access</StyledButton>
</NavMenu>
</Nav>
)
}
Notes:
I have tried to use useState to call another function here, but that doesn't seem to work, as then you have to click twice for anything to happen.
If you replace <DropDownMenu...> within the map function with a console.log, it will print out all the elements that need to appear, which is strange.
So if it can do that, and the mapping function is working correctly, why can't I see <p>{props}</p> for every item?
Use:
export function DropDownMenu({props}) {
return (
<p>{props}</p> /* same as props.props */
)
}
const Header = () => {
// const [open, setOpen] = useState(false);
return (
<Nav>
<StyledLinkBox to="/"><Logo/></StyledLinkBox>
<Bars />
<NavMenu>
{headerMenuData.map((item, index, dropdown) => (
<NavLink to={item.link} key={index} onClick={() => {
item.dropdown.map((item, index) => (
<DropDownMenu props={item} key={index}/>
))}
}>
{item.title}
</NavLink>
))}
<StyledButton>Early Access</StyledButton>
</NavMenu>
</Nav>
)
}
You are sending item as props and the component is also, by default, is getting props (if you send it), so you need to restructure it or access the data by props.props.
You can do:
<DropDownMenu item={item} key={index}/>
And:
export function DropDownMenu({item}) {
return (
<p>{item}</p> /* same as props.item */
)
}
For a more succinct approach.

Dynamic nested accordion with nested children

I am trying to build a reusable accordion, i was able to create an accordion with one level, but here i am stuck to have the nested accordion.
What i have tried so far
App.js
import "./styles.css";
import Accordion from "./Accordion";
import LIST from './Constants';
const listMaker = (item) => {
let faqItem;
if (item.children.length === 0) {
faqItem = (
<>
<Accordion title={item.name}></Accordion> <hr />
</>
);
} else {
let faqItemChildren = item.children.map((item) => {
let faqItem = listMaker(item);
return (
<>
${faqItem}
<hr />
</>
);
});
faqItem = <Accordion title={item.name}>{faqItemChildren}</Accordion>;
}
return faqItem;
};
let listItems = LIST.map((item) => {
let menuItem = listMaker(item);
return menuItem;
});
export default function App() {
return listItems;
}
have added codesandbox
I am new tor react, Any help is appreciated
Instead of using dangerouslySetInnerHTML you can use the children, as you need is a spread of React.ReactChildren. That would be just calling the {children} from props instead of the dangerouslySetInnerHTML
<div className="accordion__section">
<button className={`accordion ${setActive}`} onClick={toggleAccordion}>
<p className="accordion__title">{title}</p>
<Chevron className={`${setRotate}`} width={10} fill={"#777"} />
</button>
<div
ref={content}
style={{ maxHeight: `${setHeight}` }}
className="accordion__content"
>
{children}
</div>
</div>
Here is a forked solution of your codesandbox.
Also, Instead of setting the DOM to a variable, as its a conditional scenario, you can use the ternary operator, which helps in better readability.
const listMaker = (item) => {
return (
<>
{item.children.length === 0 ? (
<Accordion title={item.name} />
) : (
<Accordion title={item.name}>
{item.children.map((childItem) => {
return listMaker(childItem);
})}
</Accordion>
)}
</>
);
};
dangerouslySetInnerHTML is to use with strings. You shouldn't give an array of components to it. Yet you don't send any prop called content anyway. I think you meant children prop there. Just render children instead of using dangerouslySetInnerHTML
In your Accordion component replace this:
<div
className="accordion__text"
dangerouslySetInnerHTML={{ __html: props.content }}
/>
With this:
<div className="accordion__text">
{ props.children }
</div>

Cleaner react code when using loops and map

I have this code working with react, and its just getting very cluttered, so I was wondering if there is a way to make this code and others that are quite similar to look cleaner.
render() {
let result = null;
var obj = this.state.welcome;
let test = null;
if (this.state.isReal) {
test = Object.entries(obj).map(([key, value], index) => {
return (
<li key={index}>
Word: "{key}" repeats: {value} times
</li>
);
});
result = (
<Aux>
<h3>Title</h3>
<ul>{test}</ul>
</Aux>
);
}
return (
<Aux>
<div className="bframe">
<div className="form" />
{result}
</div>
<Footer />
</Aux>
);
}
I was wondering if its possible to move everything before 'return' statement, preferable in a separate file. I tried making a functional component and passing props but im unable to do loops there. Any tips?
You can reduce your code to the following :
render() {
const { welcome, isReal } = this.state
return (
<Aux>
<div className="bframe">
<div className="form" />
{isReal &&
<Aux>
<h3>Title</h3>
<ul>
{Object.entries(welcome).map(([key, value]) =>
<li key={key}>
Word: "{key}" repeats: {value} times
</li>
)}
</ul>
</Aux>
}
</div>
<Footer />
</Aux>
);
}
Do not use var, by default use const and if you want to modify your variable, use let.
You can choose to render an element or not by using the inline if : &&.
Your function is also unnecessary as it can be replaced by inline JS.
Your map can also be reduce from : x.map(a => { return <div/> } to x.map(a => <div/>.
You can also use the key of each item as the React key since they all have to be unique anyway in your object.
Maybe something like the following
const Result = ({real, welcome}) => {
if (!real) return null;
const words = Object.entries(welcome).map(([key, value], index) => <li key={index}>
Word: "{key}" repeats: {value} times
</li>
);
return (
<Aux>
<h3>Title</h3>
<ul>{words}</ul>
</Aux>
);
}
class YourComponent extends React.Component {
// ...
render() {
const {isReal, welcome} = this.state;
return (
<Aux>
<div className="bframe">
<div className="form" />
<Result real={isReal} welcome={welcome}/>
</div>
<Footer />
</Aux>
);
}
}

Categories

Resources