Estoy tratando de implementar una lógica, donde, según el elemento en el que se hizo clic, el ícono de arrow down cambia a arrow-up y si el usuario hace clic por segunda vez en la misma fila, debería cambiar nuevamente.
Intenté activarlo según el índice del elemento en el que se hizo clic, pero no funciona correctamente.
También intenté cambiar los íconos según el cambio de estado booleano como aquí
const handleClick = () => { setOpen(!open); };Pero este enfoque cambia de estado para todos los íconos en el estado.
Aquí está el código y el enlace del sandbox .
import React, { useState } from "react"; import { ListGroup } from "react-bootstrap"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faAngleUp, faAngleDown } from "@fortawesome/free-solid-svg-icons"; export const defaultListData = [ { name: "Dapibus ac facilisis in" }, { name: "Morbi leo risus" }, { name: "Porta ac consectetur ac" }, { name: "Porta ac doesfvsaard asdas" } ]; function UserSettings() { const [open, setOpen] = useState(false); const [selectedIndex, setSelectedIndex] = useState(0); const handleClick = () => { setOpen(!open); }; function handleTests(index) { setSelectedIndex(index); } return ( <div> {defaultListData.map((category, i) => ( <ListGroup key={category.name} variant="flush"> <ListGroup.Item onClick={(e) => handleTests(i)} style={{ display: "flex", gap: "50px" }} > {category.name} <FontAwesomeIcon style={{ color: "green", cursor: "pointer" }} icon={selectedIndex === i ? faAngleDown : faAngleUp} /> </ListGroup.Item> </ListGroup> ))} </div> ); } export default UserSettings;Cualquier ayuda será apreciada
Necesita mantener el estado para cada registro. Consulte el ejemplo a continuación.
import React, { useState } from "react"; import { ListGroup } from "react-bootstrap"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faAngleUp, faAngleDown } from "@fortawesome/free-solid-svg-icons"; function UserSettings() { const [open, setOpen] = useState(false); const [defaultListData, setDefaultListData] = useState([ { name: "Dapibus ac facilisis in", selected: false }, { name: "Morbi leo risus", selected: false }, { name: "Porta ac consectetur ac", selected: false }, { name: "Porta ac doesfvsaard asdas", selected: false } ]); const handleClick = () => { setOpen(!open); }; function handleTests(index) { let updateData = defaultListData.map((item, i) => { return index === i ? { ...item, selected: !item.selected } : item; }); setDefaultListData(updateData); } return ( <div> {defaultListData.map((category, i) => ( <ListGroup key={category.name} variant="flush"> <ListGroup.Item onClick={(e) => handleTests(i)} style={{ display: "flex", gap: "50px" }} > {category.name} <FontAwesomeIcon style={{ color: "green", cursor: "pointer" }} icon={category.selected ? faAngleDown : faAngleUp} /> </ListGroup.Item> </ListGroup> ))} </div> ); } export default UserSettings;Desea alternar cambiar el índice selectedIndex dependiendo de si el elemento en el que se hizo clic ya está abierto. La mejor manera sería mover el Item a un componente separado que tenga su propio estado open :
const Item = (props) => { const [open, setOpen] = useState(false); const handleClick = () => { setOpen((prev) => !prev); }; return ( <ListGroup.Item onClick={(e) => handleClick()} style={{ display: "flex", gap: "50px" }} > {props.category.name} <FontAwesomeIcon style={{ color: "green", cursor: "pointer" }} icon={open ? faAngleDown : faAngleUp} /> </ListGroup.Item> ); }; function UserSettings() { return ( <div> {defaultListData.map((category, i) => ( <ListGroup key={category.name} variant="flush"> <Item category={category} /> </ListGroup> ))} </div> ); }Esto sucede porque su ícono se cambia solo cuando se selectedIndex === i lo que significa que solo la fila en la que hizo clic será faAngleDown .
En este caso, un buen enfoque sería otra variable, como una bandera, en defaultListData y verificarla para representar el ícono correcto.
Ex.:
export const defaultListData = [ { name: "Dapibus ac facilisis in", isOpen: false }, { name: "Morbi leo risus", isOpen: false }, { name: "Porta ac consectetur ac", isOpen: false }, { name: "Porta ac doesfvsaard asdas", isOpen: false } ];