Reputation: 3259
I'm building a React application and I'm curious about one thing. I have to render a list of elements, those elements can change in nature and type of data but they share a very similar logic. Here's two of them as example:
import React, { useState } from "react";
import JSONPretty from "react-json-prettify";
import Card from "react-bootstrap/Card";
import Accordion from "react-bootstrap/Accordion";
import Button from "react-bootstrap/Button";
import ListGroup from "react-bootstrap/ListGroup";
import TransactionState from "components/TransactionState";
import timestampToDate from "helpers/timestampToDate";
function BtcTransaction({ transaction }) {
const [icon, setIcon] = useState("+");
const toggleIcon = () => {
const newIcon = icon === "+" ? "-" : "+";
setIcon(newIcon);
};
return (
<Card className="transaction-card">
<Accordion>
<Card.Body>
<Card.Title className="space-between">
<span>
BTC transaction -
<TransactionState state={transaction.state} />
</span>
<Accordion.Toggle
as={Button}
variant="primary"
size="sm"
eventKey="0"
onClick={() => toggleIcon()}
>
{icon}
</Accordion.Toggle>
</Card.Title>
<Card.Text></Card.Text>
<ListGroup variant="flush">
<ListGroup.Item>
<b>From: </b>
{transaction.from}{" "}
</ListGroup.Item>
<ListGroup.Item>
<b>To: </b>
{transaction.to}
</ListGroup.Item>
<ListGroup.Item>
<b>At: </b>
{timestampToDate(transaction.insertedAt)}
</ListGroup.Item>
<ListGroup.Item>
<b>Amount: </b>
{transaction.wholeAmount} BTC
</ListGroup.Item>
</ListGroup>
<Accordion.Collapse eventKey="0">
<JSONPretty json={transaction} />
</Accordion.Collapse>
</Card.Body>
</Accordion>
</Card>
);
}
export default BtcTransaction;
and here's another one:
import React, { useState } from "react";
import JSONPretty from "react-json-prettify";
import Card from "react-bootstrap/Card";
import Accordion from "react-bootstrap/Accordion";
import Button from "react-bootstrap/Button";
import ListGroup from "react-bootstrap/ListGroup";
import TransactionState from "components/TransactionState";
import timestampToDate from "helpers/timestampToDate";
function CustodialTransaction({ transaction }) {
const [icon, setIcon] = useState("+");
const toggleIcon = () => {
const newIcon = icon === "+" ? "-" : "+";
setIcon(newIcon);
};
return (
<Card className="transaction-card">
<Accordion>
<Card.Body>
<Card.Title className="space-between">
<span>
Custodial transaction -
<TransactionState state={transaction.state} />
</span>
<Accordion.Toggle
as={Button}
variant="primary"
size="sm"
eventKey="0"
onClick={() => toggleIcon()}
>
{icon}
</Accordion.Toggle>
</Card.Title>
<Card.Text></Card.Text>
<ListGroup variant="flush">
<ListGroup.Item>
<b>Pair: </b>
{transaction.pair}
</ListGroup.Item>
<ListGroup.Item>
<b>Type: </b>
{transaction.type}
</ListGroup.Item>
<ListGroup.Item>
<b>At: </b>
{timestampToDate(transaction.insertedAt)}
</ListGroup.Item>
<ListGroup.Item>
<b>Amount: </b>
{transaction.fiatValue} {transaction.fiatCurrency}
</ListGroup.Item>
</ListGroup>
<Accordion.Collapse eventKey="0">
<JSONPretty json={transaction} />
</Accordion.Collapse>
</Card.Body>
</Accordion>
</Card>
);
}
export default CustodialTransaction;
Let's consider the logic to toggle the details with the function: toggleIcon
and the state icon
. It's exactly the same in both components.
To have a cleaner component I would like to extract that logic but I'm not sure what's a good pattern to do that.
Here's how I render the list based on the different types:
import React from "react";
import {
BTC_TRANSACTION,
CUSTODIAL_TRANSACTION,
} from "const/const";
import BtcTransaction from "components/BtcTransaction";
import CustodialTransaction from "components/CustodialTransaction";
import generateId from "helpers/generateId";
function TransactionsList({ data }) {
return (
<div>
{data.map((el) => {
switch (el.transactionType) {
case BTC_TRANSACTION:
return <BtcTransaction key={el.id} transaction={el} />;
case CUSTODIAL_TRANSACTION:
return <CustodialTransaction key={el.id} transaction={el} />;
default:
return <div key={generateId()}>Unrecognized transaction type</div>;
}
})}
</div>
);
}
export default TransactionsList;
How can I do that?
Upvotes: 1
Views: 195
Reputation: 1099
u can create a hook to handle icons, a hook that returns an iconToggler function, and an icon state, something like this:
const useIcon = () => {
const [icon, setIcon] = React.useState('+');
const toggleIcon = () => setIcon((prev) => (prev === '+' ? '-' : '+'));
return {
icon,
toggleIcon,
};
};
function App() {
const { icon, toggleIcon } = useIcon();
return <button onClick={toggleIcon}>{icon}</button>;
}
Upvotes: 1