I have this class in React:
render() {
let addedItems = this.props.items.length ? (
this.props.items.map(item => {
return (
<li className="collection-item avatar" key={item.id}>
<div className="item-desc">
<Modal trigger={<Button onClick={this.handleOpen}>Editar</Button>}>
<Header icon="archive" content="Archive Old Messages" />
<Modal.Content>
{/* CHEESE */}
<Button.Group>
<Link to="/cart">
<Button
icon="plus"
onClick={() => {
console.log("BUT +");
this.handleCheese(item, "+");
}}
/>
</Link>
<Button content="Cheese" labelPosition="left" />
<Link to="/cart">
<Button
icon="minus"
onClick={() => {
this.handleCheese(item, "-");
}}
/>
</Link>
<h2>{item.queijo}</h2>
</Button.Group>
</Modal.Content>
</Modal>
</div>
</li>
);
})
)
}
In resume a modal should open according to the object I'm selecting.
But in my code the item.id is selecting the last object I inserted in the addedItems.
I need the modal to have the info about the obj I selected.
In case you want to see all code is in: https://github.com/fernanda-avelar/burguer_cart ->
This page is the /src/components/Cart.js
I guess you can have only one modal in your window, that's why it's taking the last one (by having overriden all others).
So instead you should put your modal out of the .map.
Also, keep track of the selected item via a controlled state selectedItem.
Then use it the the Modal.Content :
render() {
return (
<>
<Modal.Content>
/* content depending of this.state.selectedItem */
</Model.Content>
/* your other stuff */
</>
)
}
Related
enter image description herewhen i click on the reply button, it affects all the components instead of just one.
how can i achieve it to only affect the component i clicked instead of all similar components enter image description here
note: what im trying to achieve is an interactive comment section
the main comment code:
function MainComment(props) {
let [score, setScore] = useState(props.score);
const addScore = () => {
setScore(score + 1);
};
const minusScore = () => {
setScore(score - 1);
};
let { setReplyFunction } = useContext(Context);
return (
<>
{/* comment container */}
...
{/* other section in comment contaainer */}
<div className={mainComment.other}>
{/* first row */}
<div className={mainComment.otherfirstRow}>
<div className={mainComment.otherfirstRowCollumn}>
{/* user profile and username */}
<img src={props.image} alt='user' />
<span className={mainComment.userName}>
{props.userName}
</span>
{/* comment date */}
<span className={mainComment.time}>
{props.time}
</span>
</div>
{/* reply icon */}
<div
className={mainComment.replySection}
onClick={setReplyFunction}
>
<img src={iconReply} alt='reply' />
<span>reply</span>
</div>
</div>
{/* main reply */}
<div className={mainComment.otherSecondRow}>
{props.comment}
</div>
...
...
<ReplyComment />
</>
);
}
export default MainComment;
In my react project, my purpose is removing item when I click the trash icon. I tried to reach li elements using parentNode or parentElements but when I do this whenever I click the trash button console shows me different parent elements. Sometimes shows me li but sometimes icons div. I couldn't understand thats why
output is like that (img)
const removeItem = (item) => {
const liITem = item.target.parentNode.parentNode.parentNode;
console.log(liITem);
//liITem.remove();
};
return (
<Container>
<ToDoForm onSubmit={addTodo} />
<ul className="items">
{todos.map((todo) => (
<li className="item" key={todo.id}>
{todo.text}
<div className="icons">
<button className="icon">
<AiFillEdit />
</button>
<button className="icon">
<BsFillTrashFill onClick={removeItem} />
</button>
</div>
</li>
))}
</ul>
</Container>
);
You can pass the id of the item you want to remove.
const removeItem = (id) => {
const todosUpdated = todos.filter((elt) => elt.id != id )
setTodos(todosUpdated )
};
return (
<Container>
<ToDoForm onSubmit={addTodo} />
<ul className="items">
{todos.map((todo) => (
<li className="item" key={todo.id}>
{todo.text}
<div className="icons">
<button className="icon">
<AiFillEdit />
</button>
<button className="icon">
<BsFillTrashFill onClick={() => removeItem(todo.id)} />
</button>
</div>
</li>
))}
</ul>
</Container>
);
In this e-commerce project, onClick "add to cart" should increment cart count, and change button textContent to "Remove from cart", a second onClick of the same element should decrement count and change textContent back to "Add to cart". I have shown 2 different conditional syntaxes that produce opposite behaviours.
function RenderBooks({book, updateCart}) {
return(
<Card className="allbooks">
<CardBody>
<Link to="/" style={{textDecoration:'none', color:'black'}} >
<CardTitle><strong>{book.name}</strong></CardTitle>
<CardImg width="100%" src={bookImg} alt="book image" />
<CardText>{book.price}</CardText>
</Link>
<form>
<Button className="add-to-cart" style={{textDecoration:'none'}} color="link"
onClick={(e, id) => updateCart(e, book.id)}
>
Add to cart
</Button>
</form>
</CardBody>
</Card>
);
}
In the first condition of updateCart, event.target.textContent fires, but this.props.addToCart, which calls redux dispatch in the parent component, won't fire, while the reverse is the case in the else condition, that is, the dispatch function fires, and event.target doesn't. How may i get the dispatch function to fire after event.target.textContent fires, thanks in advance.
class Books extends React.Component {
constructor(props){
super(props);
this.updateCart = this.updateCart.bind(this);
}
updateCart(event, id) {
if (event.target.textContent === 'Add to cart') {
event.target.textContent = 'Remove from cart';
const count = this.props.cartcount.cartcount;
() => {
this.props.addToCart(id, count);
}
}
else {
event.target.textContent = 'Add to cart';
let count = this.props.cartcount.cartcount;
this.props.subtractFromCart(id, count);
}
}
render() {
const count = this.props.cartcount.cartcount;
const book = this.props.books.books.map((book, index) => {
return (
<div key={index} className="col-8 col-md-4 col-lg-3">
<RenderBooks book={book} updateCart={this.updateCart} />
</div>
);
});
return (
<div>
<Navbar dark expand="md" id="nav-books">
<div className="container">
<Nav className="mr-auto" navbar>
<NavItem>
<NavLink className="nav-link" to='/'>
<BsArrowLeft />
</NavLink>
</NavItem>
</Nav>
<NavbarBrand className="mc-auto logo" href="/">Soteria</NavbarBrand>
<Nav className="ml-auto" navbar>
<NavItem>
<NavLink className="nav-link" to='/'>
<FiShoppingCart /> {count}
</NavLink>
</NavItem>
</Nav>
</div>
</Navbar>
<div className="container books">
<div className="row">
{book}
</div>
</div>
</div>
);
}
}
export default Books;
I learned that redux-thunk is synchronous, so the event listener is lost by the time the store is updated. So i eventually thought up what is an intuitive react-redux solution by adding itemids param, an array that stores clicked items ids, and updating the UI in RenderBooks() with ternary operators;
function RenderBooks({book, itemids, updateCart}) {
return(
<Card>
<CardBody>
<Link to="/" style={{textDecoration:'none', color:'black'}} >
<CardTitle><strong>{book.name}</strong></CardTitle>
<CardImg width="100%" src={bookImg} alt="book image" />
<CardText>{book.price}</CardText>
</Link>
{
itemids.length != 0 ?
itemids.includes(book.id) ?
<Button onClick={(e, id) => updateCart(e, book.id)}>
Remove from cart
</Button>
:
<Button onClick={(e, id) => updateCart(e, book.id)}>
Add to cart
</Button>
:
<Button onClick={(e, id) => updateCart(e, book.id)}>
Add to cart
</Button>
}
</CardBody>
</Card>
);
}
So in updateCart, i only use event.target.textContent to determine which props.function to call.
class Books extends React.Component {
constructor(props){
super(props);
this.updateCart = this.updateCart.bind(this);
}
updateCart(event, id) {
let target = event.target.textContent;
if (target === 'Add to cart') {
this.props.addToCart(id)
}
else {
this.props.subtractFromCart(id);
}
}
render() {
const book = this.props.books.books.map((book, index) => {
return (
<div key={index} className="col-8 col-md-4 col-lg-3">
<RenderBooks book={book} itemids={this.props.itemids}
updateCart={this.updateCart}
/>
</div>
);
});
return (
<div>
<div className="container books">
<div className="row">
{book}
</div>
</div>
</div>
);
}
}
export default Books;
I am newbie in Reactjs. This is my code. I want the Link component to just wrap the Card component.
but when my codes are like this, reactjs fails me. How can I write these codes correctly ??
const ImageFrame = ({ movieId, movieName, searchWord, image, personMovieId, clickable, clearFavouriteMovie }) => {
return (
<div className = "col-sm-3 mt-5 animated fadeInLeftBig ">
{ clickable ? /* if clickable props is true --> go movie, else go movie again but with personal movie id ! */
<Link to={{ pathname:`/movie/${movieId}`, movieName: `${movieName}`, searchWord: `${searchWord}` }}>
<Card className = "card-box image-frame ">
<Card.Img variant="top" src={image} alt="movieImg" />
</Card>
</Link> **!!! I WANT Link component stays here !!!**
{
clearFavouriteMovie && <button
className = "mt-3 btn btn-warning"
onClick = { () => clearFavouriteMovie(movieId)}
> Bu Filmi Sil </button>
}
:
<Link to = {{pathname: `/movie/${personMovieId}`}}> {/* Person Known For Movies*/}
<Card className = "bg-dark text-light card-box image-frame " style = {{maxHeight: "500px"}}>
<Card.Img variant="top" src={image} alt="movieImg" />
</Card>
</Link>
}
</div>
)
An if statement can only return one element, in this case you're trying to return two <Link> and <button> to make this in to one use a <React.fragment>
Example
const ImageFrame = ({ movieId, movieName, searchWord, image, personMovieId, clickable, clearFavouriteMovie }) => {
return (
<div className = "col-sm-3 mt-5 animated fadeInLeftBig ">
{ clickable ? /* if clickable props is true --> go movie, else go movie again but with personal movie id ! */
<React.fragment>
<Link to={{ pathname:`/movie/${movieId}`, movieName: `${movieName}`, searchWord: `${searchWord}` }}>
<Card className = "card-box image-frame ">
<Card.Img variant="top" src={image} alt="movieImg" />
</Card>
</Link> **!!! I WANT Link component stays here !!!**
{
clearFavouriteMovie && <button
className = "mt-3 btn btn-warning"
onClick = { () => clearFavouriteMovie(movieId)}
> Bu Filmi Sil </button>
}
</React.fragment>
:
<Link to = {{pathname: `/movie/${personMovieId}`}}> {/* Person Known For Movies*/}
<Card className = "bg-dark text-light card-box image-frame " style = {{maxHeight: "500px"}}>
<Card.Img variant="top" src={image} alt="movieImg" />
</Card>
</Link>
}
</div>
)
This is my first time to develop a react application.
I want to add a button aligned with the pagination buttons (Previous, Next) in for navigating tables.
I've tried to do this by duplicating the Table.js that points to different component (index.js). Is there a more efficient way to add the button using 1 Table.js file, and adding a variable in the index.js as an indicator for displaying/hiding the added button? Or have a better implementation? Thank you
Display Button 1 on component 1 only
Display Button 2 on component 2 only
pagination = pageOptions.length ? (
<Pagination {...getRowProps()}>
<Cell>
<Button onClick={() => previousPage()} disabled={!canPreviousPage}>
Previous
</Button>{" "}
<Button onClick={() => nextPage()} disabled={!canNextPage}>
Next
</Button>{" "}
<span>
Page{" "}
<strong>
{pageIndex + 1} of {pageOptions.length}
</strong>{" "}
</span>
<span>
| Go to page:{" "}
<Input
type="number"
defaultValue={pageIndex + 1}
onChange={e => {
const page = e.target.value ? Number(e.target.value) - 1 : 0;
gotoPage(page);
}}
style={{ width: "100px" }}
/>
</span>{" "}
<Select
value={pageSize}
onChange={e => {
setPageSize(Number(e.target.value));
}}
>
{[10, 20, 30, 40, 50].map(pageSize => (
<option key={pageSize} value={pageSize}>
Show {pageSize}
</option>
))}
</Select>{" "}
**<Button onClick={() => test1()}>BUTTON1</Button> -> Display only on component 1
<Button onClick={() => test2()}>BUTTON2</Button> -> Display only on component 2**
</Cell>
</Pagination>
) : null;
return (
<div>
<Table {...getTableProps()}>
{headerGroups.map(headerGroup => (
<HeaderRow {...headerGroup.getRowProps()}>
{headerGroup.headers.map(column => (
<Header
{...column.getHeaderProps()}
sorted={column.sorted}
sortedDesc={column.sortedDesc}
sortedIndex={column.sortedIndex}
>
<div>
<span {...column.getSortByToggleProps()}>
{column.render("Header")}
</span>{" "}
{/* {column.canGroupBy ? (
<Emoji {...column.getGroupByToggleProps()}>
{column.grouped ? "🛑" : "👊"}
</Emoji>
) : null} */}
</div>
{column.canFilter ? <div>{column.render("Filter")}</div> : null}
</Header>
))}
</HeaderRow>
))}
{tableBody}
<Row {...getRowProps()}>
{loading ? (
<Cell>
<strong>Loading...</strong>
</Cell>
) : (
<Cell>{rows.length} Total Records</Cell>
)}
</Row>
{pagination}
</Table>
</div>
);
You should use state in this case.
And change the state from witch component is mounted right now. You can use the react lifecycle methods componentDidMount(){} and componentWillUnmount() {} for setting state.
And then just check the state and add the button.
State and Lifecycle - check the docs, it will answer a lot