I am trying to achieve a modal popup(which is stored in postview class) to appear when a onclick is called in any post on postcontainer class. I am new to react, so I would love your suggestion on improving code.
Class 1 (PostCointainer)
This is main class which shows multiple post from an array. I want the modal to appear from class 2 when any post is clicked
import React, { Component, useState } from 'react';
import '../App.css';
import PostView from './PostView';
function RenderPost({posts}) {
return (
<div className="post-holder shadow-sm p-3 mb-4 bg-white rounded" key={posts.id} onClick={class postview class 2}>
</div>
);
}
const PostContainer = props => {
const menu = props.posts.map(post => {
return (
<RenderPost posts={post} />
)
});
return (
<div className="container-fluid">
<div className="row justify-content-center">
<PostView />
{menu}
</div>
</div>
);
}
export default PostContainer;
Class 2 (post View)
class PostView extends Component {
constructor(props) {
super(props);
this.state = {
isModalOpen : true,
}
this.toggleModal = this.toggleModal.bind(this);
}
toggleModal(e) {
e.stopPropagation()
this.setState({
isModalOpen: !this.state.isModalOpen
});
}
render() {
return (
<div className="shadow-sm p-2 mb-2 bg-white">
<div
className="modal"
style={{display: this.state.isModalOpen ? 'block' : 'none' }}
onClick={this.toggleModal} >
<div
className="modal-content"
onClick={ e => e.stopPropagation() } >
<span
className="close"
onClick={this.toggleModal}
>×
</span>
<div className="container">
<h3 className="form-header">Hello</h3>
</div>
</div>
</div>
</div>
);
}
}
export default PostView;
This can be simply acheived by maintaining a state variabe for post click in the parent component and passing it via prop to child.
PostContainer.js
import React, { Component, useState } from 'react';
import '../App.css';
import PostView from './PostView';
const PostContainer = props => {
const [post, setPost] = useState(false);
function RenderPost({posts}) {
return (
<div className="post-holder shadow-sm p-3 mb-4 bg-white rounded" key={posts.id} onClick={setPost(posts)}>
</div>
);
}
const menu = props.posts.map(post => {
return (
<RenderPost posts={post} />
)
});
return (
<div className="container-fluid">
<div className="row justify-content-center">
<PostView post={post} />
{menu}
</div>
</div>
);
}
export default PostContainer;
Constructor function of PostView Component
constructor(props) {
super(props);
this.state = {
isModalOpen : !!props.post,
}
this.toggleModal = this.toggleModal.bind(this);
}
And you can use the same post prop to render post in render function of your child component.
Hope it helps!!
Related
I have a parent component that contains a modal which I want to show/hide onClick of an element in a child component. How can I now basically call that handler in the parent company from the child component click?
My idea was to somehow provide the handler via the props from the parent to the child:
// parent components
import PlannerDetails from "./PlannerDetails";
import PlannerTools from "./PlannerTools";
import {useState} from "react";
const PlannerWrapper = () => {
const [showTools, setShowTools] = useState(false)
const toolsHandler = () => {
setShowTools(true)
}
return (
<div className="wrapper w-6/6 h-full flex bg-dotted bg-sx-white">
<div className="right-wrapper w-3/6 h-full p-8">
<div className="details-wrapper w-full h-full bg-sx-white-plain rounded-2xl shadow-sx-shadow">
<PlannerDetails/>
</div>
</div>
{showTools ? <PlannerTools/> : null}
</div>
)
}
export default PlannerWrapper
// child component
import imageEdit from "../../assets/images/edit.svg"
const PlannerDetails = (props) => {
return (
<div className="details-wrapper">
<div className="details-head flex border-b-1 border-b-gray">
<div className="text-2xl text-sx-purple-dark p-4">Offer Details</div>
<div className="icon-wrapper flex">
<img src={imageEdit} className="w-4 cursor-pointer"
onClick={props.toolsHandler}/> // <--------- click event here
</div>
</div>
</div>
)
}
export default PlannerDetails
Updated approach
// Parent
import PlannerDetails from "./PlannerDetails";
import PlannerTools from "./PlannerTools";
import {useState} from "react";
const PlannerWrapper = () => {
const [showTools, setShowTools] = useState(false)
const toolsHandler = () => {
console.log('test')
setShowTools(true)
}
return (
<div className="wrapper w-6/6 h-full flex bg-dotted bg-sx-white">
<div className="right-wrapper w-3/6 h-full p-8">
<div className="details-wrapper w-full h-full bg-sx-white-plain rounded-2xl shadow-sx-shadow">
<PlannerDetails toolsHandler={toolsHandler} />
</div>
</div>
{showTools ? <PlannerTools/> : null}
</div>
)
}
export default PlannerWrapper
// Child
import imageEdit from "../../assets/images/edit.svg"
const PlannerDetails = (toolsHandler, ...props) => {
return (
<div className="details-wrapper">
<div className="details-head flex border-b-1 border-b-gray">
<div className="text-2xl text-sx-purple-dark p-4">Offer Details</div>
<div className="icon-wrapper flex">
<img src={imageEdit} className="w-4 cursor-pointer" alt="editTools" onClick={props.toolsHandler}/>
</div>
</div>
</div>
)
}
export default PlannerDetails
You are very close to the answer, You just need to pass the function in your parent component to the child.
like this
<PlannerDetails toolsHandler={toolsHandler} />
the first toolsHandler is the prop property in the child component, the second toolsHandler is the function in parents component.
I want to return a component <SaveTask/> to a div tag where <div id="saveTask">. I tried to use this.setState(), but it changes the container and displays the <SaveTask/> component. I want to keep that container and under that container, I want to append a component after clicking a button. Is there any way to add component using document.getElementById('saveTask').
import React, { Component } from 'react'
import SaveTask from './SaveTask';
export default class TaskHeader extends Component {
constructor(props) {
super(props)
this.state = {
saveTask: false,
}
this.showComp = () => {
this.setState({
saveTask: true,
})
}
}
render() {
if(this.state.saveTask) {
return (
document.getElementById('saveTask').innerHTML = <SaveTask/>
)
}
return (
<div>
<div className="container-fluid bg-white border-bottom">
<div className="row">
<div className="col-12">
<div className="tasks-upper text-muted">TASK MANAGEMENT APP</div>
<div className="tasks-lower">
<span className="text-secondary text-size">TASK</span><button className="text-primary btn-size" type="button" onClick={this.showComp}>+</button>
</div>
</div>
</div>
</div>
<div id="saveTask">
Return a component to this section when clicking the button
</div>
</div>
)
}
}
Yeah, so the beauty of react is that you don't need to and shouldn't be updating the innerhtml to update a component. You can simply use a ternary to determine what component to show later on:
import React, { Component } from 'react'
import SaveTask from './SaveTask';
export default class TaskHeader extends Component {
constructor(props) {
super(props)
this.state = {
saveTask: false,
}
this.showComp = () => {
this.setState({
saveTask: true,
})
}
}
render() {
return (
<div>
<div className="container-fluid bg-white border-bottom">
<div className="row">
<div className="col-12">
<div className="tasks-upper text-muted">TASK MANAGEMENT APP</div>
<div className="tasks-lower">
<span className="text-secondary text-size">TASK</span><button className="text-primary btn-size" type="button" onClick={this.showComp}>+</button>
</div>
</div>
</div>
</div>
{this.state.saveTask ? (
<SaveTask/>
) : (
<div id="saveTask">
Return a component to this section when clicking the button
</div>
)}
</div>
)
}
}
In this case you're saying, "if this.state.saveTask is true, then show <SaveTask /> otherwise, show the <div id="saveTask"> element. If you wanted inside that div, then you would just move the ternary inside it.
I hope following answer will help you
Achive using Functional Component
import React, { useState } from "react";
import SaveTask from "./SaveTask";
function TaskHeader() {
const [show, setShow] = useState(false);
const showComp = () => {
setShow(true);
};
return (
<div>
<div className="container-fluid bg-white border-bottom">
<div className="row">
<div className="col-12">
<div className="tasks-upper text-muted">TASK MANAGEMENT APP</div>
<div className="tasks-lower">
<span className="text-secondary text-size">TASK</span>
<button
className="text-primary btn-size"
type="button"
onClick={showComp}
>
+
</button>
</div>
</div>
</div>
</div>
<div id="saveTask">{show && <SaveTask />}</div>
</div>
);
}
export default TaskHeader;
Achive using Class Component
import React, { Component } from 'react'
import SaveTask from './SaveTask';
export default class TaskHeader extends Component {
constructor(props) {
super(props)
this.state = {
saveTask: false,
}
this.showComp = () => {
this.setState({
saveTask: true,
})
}
}
render() {
return (
<div>
<div className="container-fluid bg-white border-bottom">
<div className="row">
<div className="col-12">
<div className="tasks-upper text-muted">TASK MANAGEMENT APP</div>
<div className="tasks-lower">
<span className="text-secondary text-size">TASK</span><button className="text-primary btn-size" type="button" onClick={this.showComp}>+</button>
</div>
</div>
</div>
</div>
<div id="saveTask">`
{ this.state.saveTask && <SaveTask/> }
</div>
</div>
)
}
}
I'm trying to delete multiple items at once for checkboxes in REACT, but the code does not seem to delete the items being checked.
Here's my approach to doing this. I made a function in tasks.jsx file
called add_ids_to_be_deleted to append the id that was being checked
in the checkbox to an array of ids to be deleted called list_of_ids.
This function is called in the child component in priorityLists.jsx.
When the user clicks the delete button, I created a useEffect to
filter out all the items in toDo whose ids are not included in the ids
to be deleted.
The problem is it keeps deleting the last item whenever I check a checkbox regardless of the order.
For example, I add 3 checkboxes and
check the first checkbox to delete it. Instead of the first checkbox
being deleted, the last item is deleted even though it wasn't being
checked.
tasks.jsx
import React, { useState, useEffect } from 'react';
import { Delete, Refresh, Add } from '../components/Actions';
import { Header } from '../components/Header';
import ToDoList from '../components/TaskList';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import { faPlus, faTrash } from '#fortawesome/free-solid-svg-icons';
import { v4 as uuidv4 } from 'uuid';
function Task() {
const [toDo, setToDo] = useState([]);
const [idsToRefresh, setIdsToRefresh] = useState([]);
const [list_of_Ids, setIds] = useState([]);
const [filter_now, setFilterNow] = useState(false);
function addToDos() {
const id = uuidv4();
setToDo(
toDo.concat({
_isKey: id,
_checked: false,
value: <ToDoList _onDelete={add_Ids_ToBe_Deleted} _key={id} />
})
);
setIdsToRefresh(idsToRefresh.concat(id));
}
function switchNow() {
if (!filter_now) {
setFilterNow(true);
} else {
setFilterNow(false);
}
}
useEffect(() => {
if (toDo[0] !== undefined) {
setToDo(
toDo.filter(item => {
return !list_of_Ids.includes(item._isKey);
})
);
}
}, [filter_now]);
function add_Ids_ToBe_Deleted(_id_ToBe_Deleted) {
setIds(item => [...item, _id_ToBe_Deleted]);
}
function refresh() {
setToDo(
toDo.filter(item => {
return !idsToRefresh.includes(item._isKey);
})
);
}
return (
<div className="main-content">
<div className="container-fluid">
<div className="row underline">
<div className="col">
<div className="row">
<div className="col-3 pt-2">
<Refresh _refresh={refresh} />
</div>
<div className="col-6 text-center">
<Header header={'Tasks'} />
</div>
<div className="col-3 pt-2">
<button className="float-right">
<FontAwesomeIcon
onClick={switchNow}
icon={faTrash}
size="2x"
/>
</button>
</div>
</div>
</div>
</div>
<div className="row">
<div className="col">
{toDo.map(item => {
return (
<div>
<ul>
<li>{item.value}</li>
</ul>
</div>
);
})}
</div>
</div>
<div className="row">
<div className="col pr-4">
<button onClick={addToDos} className="float-right" name="add">
<FontAwesomeIcon icon={faPlus} size="2x" />
</button>
</div>
</div>
</div>
</div>
);
}
export default Task;
Tasklist.jsx
import React from 'react';
import { PriorityLists } from '../components/PriorityLists';
import { Priority } from './Actions';
function ToDoList(props) {
return (
<PriorityLists
_onDelete={props._onDelete}
keys={props._key}
name="toDoList"
>
<Priority />
</PriorityLists>
);
}
export default ToDoList;
Prioritylists.jsx
import React, { useState, useEffect } from 'react';
import { Priority } from './Actions';
function PriorityLists(props) {
return (
<form>
<div className="input-group mb-3">
<div className="input-group-prepend">
<div className="input-group-text">
<input
is_checked={false}
unique_Key={props.keys}
onClick={e =>
props._onDelete(
e.target.attributes.getNamedItem('unique_Key').value
)
}
id="check-item"
type="checkbox"
aria-label="Checkbox for following text input"
/>
</div>
</div>
<textarea class="form-control" rows="1" name={props.name}></textarea>
{props.children}
</div>
</form>
);
}
export { PriorityLists };
I've hit a wall and have no clue what to do. I'm simply trying to close my bootstrap modal but it just won't close. It opens fine but again it just won't close. I've tried so many ways to rectify this that there won't be enough space on this post to list all my attempts.
What am I doing wrong and how can I fix this?
Here's App.js:
import React, { Component } from 'react';
import Product from './Product';
import { ProductConsumer } from "../context";
import TitleBody from "./TitleBody";
import AboutButton from "./AboutButton";
import AboutButtonModal from "./AboutButtonModal";
export default class App extends Component {
constructor(props) {
console.log("Props - ", props);
super(props);
this.state = {
modalVisible: false
};
this.openModal = this.openModal.bind(this);
}
openModal() {
console.log("Open modal called ", this.state.modalVisible);
const modalVisible = !this.state.modalVisible;
this.setState({
modalVisible
}, console.log(this.state.modalVisible));
}
render() {
let styles = this.state.modalVisible
? { display: "block" }
: { display: "none" };
return (
<React.Fragment>
<div className="py-5">
<div className="container">
<TitleBody name="Welcome to" title="Cruskip"/>
<AboutButtonModal show={this.state.modalVisible} onClick={this.openModal} style={styles}/>
<AboutButton onClick={this.openModal}/>
</div>
</div>
</div>
</React.Fragment>
);
}
}
Here's AboutButtonModal.js:
import React from 'react';
import './AboutButtonModal.scss';
const Modal = ({ handleClose, show, children}, props) => {
const showHideClassname = show ? "modal display-block" : "modal display-none";
return(
<div className={showHideClassname} style={props.style}>
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
onClick={props.onClick}
className="close"
>
×
</button>
<h4 className="modal-title">Modal Header</h4>
</div>
<div className="modal-body">
<p>Some text in the modal.</p>
</div>
<div className="modal-footer">
<button
onClick={props.onClick}
type="button"
className="btn btn-default"
>
Close
</button>
</div>
</div>
</div>
</div>
);
};
export default Modal;
Here's AboutButton.js:
import React from 'react';
import './AboutButton.scss';
const AboutButton = (props) => {
return(
<div className="row">
<button className="about-btn" type="button" onClick={props.onClick}>
About Us
</button>
</div>
);
};
export default AboutButton;
If you are using ({ handleClose, show, children }, props),It won't give you to access of props onClick function..
So to use props, just apply object destructing of props..Now,Your code will become like this...
const Modal = ({ handleClose, show, children,...props})
I am trying to generate a random user information when pressing the button, and display the information above the button. In ProfilePanel.js, I created a avatar and user constants, which will use to show the information. In index.js, the avatar constant works for that since it doesn't need to use the Button. however, for user constant, it doesn't work. In below's code, I am fetching a api data to display user name, but it didn't show anything, I am not sure where wrong, is something wrong in Button.js or index.js. and how can I fix it. Can somebody help me out? Thanks.
<Button title="name" >
<p key={contact.name} user={contact.name}></p>
</Button>
index.js
import React, { Component } from "react";
import ReactDOM from "react-dom";
import Panel from "./ProfilePanel";
import axios from 'axios';
import './index.css';
import Button from './Button';
const url = 'https://randomuser.me/api/';
class App extends Component {
constructor(props) {
super(props);
this.state = {
contacts: []
}
}
componentDidMount() {
this.fetchdata();
}
fetchdata() {
axios.get(url)
.then(res => {
console.log(res);
this.setState({ contacts: res.data.results});
});
}
render(){
const {contacts} = this.state;
return (
<div className="panel">
{contacts.map(contact => (
<div class="panel">
<Panel
key={contact.picture} avatar={contact.picture.medium}
/>
<li class="flex-container">
<Button title="name" >
<p key={contact.name} user={contact.name}></p>
</Button>
<Button title="location" onClick={this.fetchdata}>
</Button>
<Button key={contact.email} title="email">
</Button>
<Button key={contact.phone} title="phone">
</Button>
<Button key={contact.login.password} title="password">
</Button>
</li>
</div>
))}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById("root")
);
ProfilePanel.js
import React, { Component } from "react";
import PropTypes from "prop-types";
import './index.css';
import Button from './Button';
const style={
borderRadius: 150,
margin: 15,
}
class Panel extends Component {
render() {
const { avatar, user } = this.props;
return (
<div className="Panel">
<div class="panels">
<div className="avatar">
<img src={avatar} class="imageStyle" alt="" width={"200%"} height={"auto"}/>
</div>
</div>
<div class="center">
<h2 className="user">{user}</h2>
</div>
</div>
);
}
}
export default Panel;
Button.js
import './index.css';
import React, { Component } from 'react';
class Button extends Component {
constructor(props) {
super(props);
this.state = {
open:false,
};
}
render() {
const { title } = this.props;
const {open} = this.state;
return (
<button className={` ${open ? 'open' : ''}`}
class='button' onClick={(e) => this.handleClick(e)}>
<div className="panel-heading">
<h2 class='buttoncenter'>{title}</h2>
</div>
</button>
);
}
handleClick(e) {
e.preventDefault();
this.setState({
open: this.state.open
})
}
}
export default Button;
You're not changing state in the handle click. You need to set open to true;
handleClick(e) {
e.preventDefault();
this.setState({
open: true
})
}
You need to pass your user information in index.js. I think you have missed to pass the user props to the panel component, so that it shows the avatar alone. Without passing the users props, you are trying to destructure there in panel component.
//index.js should be like this
render(){
const {contacts} = this.state;
return (
<div className="panel">
{contacts.map(contact => (
<div class="panel">
<Panel
key={contact.picture} user={contact.name} avatar={contact.picture.medium}
/>
<li class="flex-container">
<Button title="name" >
<p key={contact.name} user={contact.name}></p>
</Button>
<Button title="location" onClick={this.fetchdata}>
</Button>
<Button key={contact.email} title="email">
</Button>
<Button key={contact.phone} title="phone">
</Button>
<Button key={contact.login.password} title="password">
</Button>
</li>
</div>
))}
</div>
);
}