Tranfser props to sibling component - javascript

Instead of% username%, I would like the current name and name to be displayed in the modal title
user's surname. I can't make this task. I
after solving the problem, give ideas how I can optimize my code.
Code:
class App extends React.Component {
state= {
show: false,
};
showModal = () =>{
this.setState({
show: !this.state.show
});
};
render() {
const users = this.props.data.users;
const userList = users.map(user => <User key={user.id} user={user} onOpen={this.showModal} name={user.name} surname={user.surname}/>)
return (
<div className="container">
{userList}
{this.state.show ? < Modal onClose={this.showModal} show={this.state.show}/> : null}
</div>
)
}
}
class User extends React.Component{
onOpen = () => {
this.props.onOpen && this.props.onOpen();
};
render(){
const {avatar, name, surname, city, country} = this.props.user;
return(
<div className="box">
<img src={avatar} alt="" className="avatar" />
<h3 className="box-title">{`${name} ${surname}`}</h3>
<p className="box-description">{`${city}, ${country}`}</p>
<div className="button-wrap">
<a href="#" className="button" onClick={()=> this.onOpen()} >Report user</a>
</div>
</div>
)
}
}
class Modal extends React.Component {
onClose = () => {
this.props.onClose && this.props.onClose();
};
render() {
if(!this.props.show){
return null;
}
// tak wygląda struktura HTML dla modal boxa
return (
<div className="modal">
<div className="modal-background"></div>
<div className="modal-content">
<div className="box">
<h3 className="modal-title">Report user</h3>
<textarea rows="6"></textarea>
<div className="button-wrap">
<a href="#" className="button button-link" onClick={() => {
this.onClose()}}>Cancel</a>
<a href="#" className="button ml-auto" onClick={()=> alert("ok")}>Report</a>
</div>
</div>
</div>
</div>
)
}
}
ReactDOM.render(<App data={data} />, document.querySelector("#app"))

using state ReportUsr to store the user you want to report changed by function this.ReportUsr in App class then pass function as prop Report to User class to call it OnClick with the value surname for that instance of User component
then Modal component created from App class has CONTENT which is the App.state.ReportUsr
< Modal onClose={this.showModal} show={this.state.show} >{this.state.ReportUsr}</ Modal>
LiveExample
https://h4i1e.csb.app/
Code https://codesandbox.io/s/modern-browser-h4i1e

Related

how to create the input div on clicking the reply button of a comment below that particular comment using react

I want on clicking the reply button the div to write the reply to come
I tried to create a seperate component for reply textarea but as I am a beginner in react I am not able to get an idea how to do it.
Comment.js
import Userdata from "./data.json";
import Score from "./Score";
import Person from "./person";
import Reply from "./Reply";
const Comment = () => {
return (<div className="sample">{
Userdata.comments.map((comment, index) => {
return (
<div key={comment.id}>
<div className="comment">
<Score score={comment.score} />
<div>
<Person user={comment.user} />
<span className="time">{comment.createdAt}</span>
<Reply index={index} />
<p>{comment.content}</p>
</div>
</div>
{comment.replies.map((reply) => {
return (
<div key={reply.id}>
<div className="comment reply">
<Score score={reply.score} />
<div>
<Person user={reply.user} />
<span>{reply.createdAt}</span>
<Reply />
<p>{reply.content}</p>
</div>
</div>
</div>
);
})}
</div>
);
})
}
</div>
);
}
export default Comment;
Reply Component
const Reply = (props) => {
const handleClick = () => {
console.log(`reply of ${props.index}`)
}
return (
<div onClick= {handleClick} className="btn-reply">
<img className="reply-icon" src="images/icon-reply.svg" alt="reply" />
<span>Reply</span>
</div>
);
}
export default Reply;

Update Component in react after clicking in parent

I am starting to learn react so I am still grasping some concepts, now I am doing something where I need to update/render a component after one in selected in the parent one, I've read about lifting up the state, but the stuff I've done it does not work, and I have no idea what I might be doing wrong.
The first component Parent:
constructor(props) {
super(props);
this.state = { selectedDish: null, }
this.onDishSelect = this.onDishSelect.bind(this);
}
onDishSelect(selectedDish) {
this.setState({ selectedDish });
}
render() {
const menu = this.props.dishes.map((dish) => {
return (
<div className="col-12 col-md-5 m-1">
<Card key={dish.id}
onClick={() => this.onDishSelect(dish)}>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
});
return (
<div className="container">
<div className="row">
{menu}
</div>
<DishDetail onClick={this.onDishSelect} />
</div>
);
}
}
export default Menu;
and the child
export default class DishDetail extends Component {
constructor(props) {
super(props);
this.state = { selectedDish: null }
this.renderDish = this.renderDish.bind(this);
}
renderDish(dish) {
if (dish != null)
return (
<Card>
<CardImg top src={dish.image} alt={dish.name} />
<CardBody>
<CardTitle>{dish.name}</CardTitle>
<CardText>{dish.description}</CardText>
</CardBody>
</Card>
);
else
return (
<div></div>
);
}
render() {
return (
<div className="row">
<div className="col-12 col-md-5 m-1">
{this.renderDish(this.props.selectedDish)}
</div>
</div>
)
}
}
When I run it I am able to see the cards of the menu, the idea is that when I click a component from the menu I can see the details in another card of the one cliked, but it is not updated, the detail component is not shown/displayed/rendered
Any Idea what I am doing wrong or missing, thanks in advance.
Your wrong is where you passed onClick to DishDetail component you should pass selectedDish to DishDetail
parent component
constructor(props) {
super(props);
this.state = { selectedDish: null, }
this.onDishSelect = this.onDishSelect.bind(this);
}
onDishSelect(selectedDish) {
this.setState({ selectedDish });
}
render() {
const menu = this.props.dishes.map((dish) => {
return (
<div className="col-12 col-md-5 m-1">
<Card key={dish.id}
onClick={() => this.onDishSelect(dish)}>
<CardImg width="100%" src={dish.image} alt={dish.name} />
<CardImgOverlay>
<CardTitle>{dish.name}</CardTitle>
</CardImgOverlay>
</Card>
</div>
);
});
return (
<div className="container">
<div className="row">
{menu}
</div>
<DishDetail selectedDish={this.state.selectedDish} /> //add selectedDish here
</div>
);
}
}
DishDetail should accept a prop called Dish and that is it. It shouldn't have any state.
// parent render function
const { selectedDish } = this.state;
return (
<div className="container">
<div className="row">
{menu}
</div>
{selectedDish && <DishDetail dish={selectedDish} />}
</div>
);
// DishDetail
class DishDetail extends Component {
render() {
return (
<div className="row">
<div className="col-12 col-md-5 m-1">
{/* some jsx with this.props.dish */}
</div>
</div>
)
}
}
To keep things simple, you could even make DishDetail a function instead of a class:
export const DishDetail = ({dish}) => (
<div className="row">
<div className="col-12 col-md-5 m-1">
{/* some jsx with dish */}
</div>
</div>
);

How to update Event.target after props.function in child component is dispatched to redux-thunk onClick

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;

React toggle class

I want toggle class only click element. But now when i click anyone they are all active. And when i click a tag, i want add another class to card div. How should i update the code?
handleClick() {
const currentState = this.state.active;
this.setState({ active: !currentState });
}
<div className="container">
<div>
<h1>Components</h1>
<div>
<a href="#" onClick={this.handleClick.bind(this)} className= {this.state.active ? "card-icon active" : "card-icon"}>click</a>
<a href="#" onClick={this.handleClick.bind(this)} className= {this.state.active ? "list-icon active" : "list-icon"}>click</a>
</div>
</div>
<input type="text" placeholder="" className="input" onChange={(e)=>this.searchSpace(e)} />
<div className="card">
{items}
</div>
</div>
You are only tracking the state with one variable (active), but you need to keep track of each state separately. Try this:
Updated to handle toggle:
handleClick() {
const currentState = this.state.active;
this.setState({ active: !currentState });
}
<div className="container">
<div>
<h1>Components</h1>
<div>
<a href="#" onClick={this.handleClick.bind(this)} className= {this.state.active ? "card-icon active" : "card-icon"}>click</a>
<a href="#" onClick={this.handleClick.bind(this)} className= {!this.state.active ? "list-icon active" : "list-icon"}>click</a>
</div>
</div>
<input type="text" placeholder="" className="input" onChange={(e)=>this.searchSpace(e)} />
<div className={this.state.active ? "card" : "list"}>
{items}
</div>
</div>
You should be using multiple state variables and also use function to update the state, so when you set cart-icon to active the list-icon state does not change.
See the example below. let me know if it helps.
class MyComp extends React.Component {
constructor(props) {
super(props);
this.state = {
cartIconActive: false,
listIconActive: false,
};
this.handleCartIconClick = this.handleCartIconClick.bind(this);
this.handleListIconClick = this.handleListIconClick.bind(this);
}
handleCartIconClick() {
this.setState((prevState) => ({
...prevState,
cartIconActive: !prevState.cartIconActive,
}));
}
handleListIconClick() {
this.setState((prevState) => ({
...prevState,
listIconActive: !prevState.listIconActive,
}));
}
render() {
const { cartIconActive, listIconActive } = this.state;
return (
<div className="container">
<div>
<h1>Components</h1>
<div>
<a
href="#"
onClick={this.handleCartIconClick}
className={cartIconActive ? 'card-icon active' : 'card-icon'}
>
click
</a>
<a
href="#"
onClick={this.handleListIconClick}
className={listIconActive ? 'list-icon active' : 'list-icon'}
>
click
</a>
</div>
</div>
<input
type="text"
placeholder=""
className="input"
onChange={(e) => this.searchSpace(e)}
/>
<div className="card">{items}</div>
</div>
);
}
}
You can also do this with
function MyComponent (props) {
const [isActive, setActive] = useState(false);
const toggleClass = () => {
setActive(!isActive);
};
return (
<div
className={isActive ? 'your_className': null}
onClick={toggleClass}
>
<p>{props.text}</p>
</div>
);
}

My component 'Recipe Items' is being rendered in a single column, when the correct one for each row is 5 columns

I have to render a component from an .json file, until then okay, to be able to read and pass the api values ​​to my component ('RecipeItem'). The problem lies in the part of rendering, because the correct one would be the components being in 5 columns instead of only one.
enter image description here
updated codes below !!!
File RecipeItem.js
const RecipeList = ({ searchString }) => {
return(
<div>
{console.log('to aqui')}
<img className="card-img-top img-fluid" src={searchString.thumbnail} alt={searchString.title} />
<div className="card-body">
<h5 className="card-title">{searchString.title}</h5>
<p className="card-text">
<strong>Ingredients: </strong>{searchString.ingredients}
</p>
</div>
</div>
)
}
const RecipeItem = (props) => {
return (
<div className="col-sm-3 mt-4">
<div className="card">
{props.list && props.list.map((searchString, index) =>
<RecipeList searchString={searchString} key={index} />
)}
</div>
</div>
)
}
File App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
searchString: []
};
}
componentDidMount() {
this.setState({ searchString : data.results })
}
render() {
return (
<div className="App">
<Navbar />
<div className="container mt-10">
<div className="row">
<RecipeItem list={this.state.searchString}/>
</div>
</div>
</div>
);
}
}
Is this working ?
class App extends Component {
render() {
return (
<div className="App">
<Navbar />
<div className="container mt-10">
<div className="row">
{RecipesData.results.map(recipe =>
<RecipeItem
title={recipe.title}
ingredients={recipe.ingredients}
source={recipe.href}
thumbnail={recipe.thumbnail} />
)}
</div>
</div>
</div>
);
}
}

Categories