After clicking button component should render EditChannel Component should render - reactjs

After clicking Button EditChannel component should render. Right now if I before clicking on button EditChannel re-rendering as many as times as list item. After clicking also happening the same. I only want after clicking on button. Please find below lines for code. After clicking EditChannel component should render
Channel card component
import React, { Fragment } from "react";
import { makeStyles } from "#material-ui/core/styles";
import { Typography, Button } from "#material-ui/core";
import Avatar from "#material-ui/core/Avatar";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { channelFollow, channelFetchById } from "../../../redux/action/channel";
import EditChannel from "../../Channels/List/Edit";
const ChannelCard = props => {
const classes = useStyles();
const { channel, channelFetchById } = props;
const [open, setOpen] = React.useState(false);
const handleClickOpen = () => {
setOpen(true);
};
const view = (
<div className={classes.card}>
<Link to={`/channels/${channel._id}`} className={classes.link}>
<div className={classes.root}>
<Avatar
alt="Remy Sharp"
src={channel.avatar}
className={classes.bigAvatar}
/>
</div>
<div className={classes.title}>
<Typography
variant="subtitle1"
align="center"
className={classes.text}
>
{channel.channelName}
</Typography>
<Typography variant="body2" align="center">
{channel.introduction}
</Typography>
</div>
</Link>
<Typography variant="body2" align="center" className={classes.text1}>
{channel.follows ? channel.follows.length : 0} followers <br />
Language:{channel.language}
</Typography>
<div className={classes.center}>
<div className={classes.button}>
<div className={classes.buttons}>
<Button
variant="contained"
color="primary"
onClick={() => {
channelFetchById(channel._id);
handleClickOpen();
}}
>
Edit
</Button>
{handleClickOpen ? (
<EditChannel setOpen={setOpen} open={open} />
) : null}
</div>
<div>
<Button color="primary" variant="contained">
Delete
</Button>
</div>
</div>
<br />
</div>
</div>
);
return <Fragment>{view}</Fragment>;
};
export default connect(null, { channelFollow, channelFetchById })(ChannelCard);

I guess instead of handleClickOpen only open will work like this,
{open ? (
<EditChannel setOpen={setOpen} open={open} />
) : null}
Because handleClickOpen is click event not boolean variable

Related

setCurrentId(prop) is not a function in reactjs

I am getting this error message in console (Uncaught TypeError: setCurrentId is not a function
at onClick (Post.js:19:1) )
I don't know how to handle this error
This is Child Component Post.js
import { Button, Card,CardActions,CardContent,CardMedia,Typography } from '#material-ui/core';
import React from 'react';
import useStyles from "./styles";
import MoreHorizIcon from '#mui/icons-material/MoreHoriz';
import DeleteIcon from '#mui/icons-material/Delete';
import ThumbUpAltIcon from '#mui/icons-material/ThumbUpAlt';
import moment from 'moment';
const Post= ({post , setCurrentId})=>{
const classes = useStyles();
return(
<Card className={classes.card}>
<CardMedia className={classes.media} image={post.selectedFile} title={post.title}/>
<div className={classes.overlay}>
<Typography variant='h6'>{post.creator}</Typography>
<Typography variant='body2'>{moment(post.createdAt).fromNow()}</Typography>
</div>
<div className={classes.overlay2}>
<Button style={{ color: 'white' }} size="small" onClick={() => setCurrentId(post._id)}><MoreHorizIcon fontSize="default" /></Button>
</div>
<div className={classes.details}>
<Typography variant='body2' color='textSecondary'>{post.tags.map((tag)=>`#${tag} `)}</Typography>
</div>
<CardContent>
<Typography className={classes.title} variant='h5' gutterBottom>{post.message}</Typography>
</CardContent>
<CardActions className={classes.cardActions}>
<Button size = 'small' color='primary' onClick={()=>{}}>
<ThumbUpAltIcon fontSize='small'/>
Like
{post.likeCount}
</Button>
<Button size = 'small' color='primary' onClick={()=>{}}>
<DeleteIcon fontSize='small'/>
Delete
</Button>
</CardActions>
</Card>
)
}
export default Post;
This is parent Component
import React from 'react';
import { Grid, CircularProgress } from '#material-ui/core';
import { useSelector } from 'react-redux';
import Post from './Post/Post';
import useStyles from './styles';
const Posts = ({ setCurrentId }) => {
const posts = useSelector((state) => state.posts);
const classes = useStyles();
return (
!posts.length ? <CircularProgress /> : (
<Grid className={classes.container} container alignItems="stretch" spacing={3}>
{posts.map((post) => (
<Grid key={post._id} item xs={12} sm={6} md={6}>
<Post post={post} setCurrentId={setCurrentId} />
</Grid>
))}
</Grid>
)
);
};
This is main file App.js
import React, { useState, useEffect } from 'react';
import { Container, AppBar, Typography, Grow, Grid } from '#material-ui/core';
import { useDispatch } from 'react-redux';
import Posts from './components/Posts/Posts';
import Form from './components/Form/Form';
import { getPosts } from './actions/posts';
import useStyles from './styles';
import memories from './images/memories.png';
const App = () => {
const [currentId, setCurrentId] = useState(0);
const dispatch = useDispatch();
const classes = useStyles();
useEffect(() => {
dispatch(getPosts());
}, [currentId, dispatch]);
return (
<Container maxWidth="lg">
<AppBar className={classes.appBar} position="static" color="inherit">
<Typography className={classes.heading} variant="h2" align="center">Memories</Typography>
<img className={classes.image} src={memories} alt="icon" height="60" />
</AppBar>
<Grow in>
<Container>
<Grid container justify="space-between" alignItems="stretch" spacing={3}>
<Grid item xs={12} sm={7}>
<Posts setCurrentId={setCurrentId} />
</Grid>
<Grid item xs={12} sm={4}>
<Form currentId={currentId} setCurrentId={setCurrentId} />
</Grid>
</Grid>
</Container>
</Grow>
</Container>
);
};
export default App;
I am trying to debug my react code and expecting something that I missed

Chakra UI Modal not working as it is supposed to

I was following the documentation of chakra UI. Here is the documentation of chakra ui. But it is not working as it is supposed to do whenever I trigger the hook the screen goes blank.
Below is the code sample. The modal is placed at the end of the file.
DialogModal Component which is imported from DialogModal.js file
import React from "react";
import {
Avatar,
Box,
Collapse,
DrawerContent,
DrawerOverlay,
Flex,
Icon,
IconButton,
Input,
InputGroup,
InputLeftElement,
Text,
useColorModeValue,
useDisclosure,
useColorMode,
Button,
Drawer,
} from "#chakra-ui/react";
import {AddIcon} from '#chakra-ui/icons';
import { FaBell, FaClipboardCheck, FaRss } from "react-icons/fa";
import { FaMoon, FaSun } from "react-icons/fa";
import { AiFillGift } from "react-icons/ai";
import { BsGearFill } from "react-icons/bs";
import { FiMenu, FiSearch } from "react-icons/fi";
import { HiCode, HiCollection } from "react-icons/hi";
import { MdHome, MdKeyboardArrowRight } from "react-icons/md";
import { BrowserRouter, Switch, Route,useRouteMatch } from 'react-router-dom';
import DonationBasedForm from '../../components/CreateDonationBased/CreateDonationBased'
import Campaigns from "../Campaigns/Campaigns";
import CreateCampaign from "../../components/CreateCampaign/CreateCampaign";
import DialogModal from "../../components/Modal/DialogModal";
import DonationBasedCampaigns from "../DonationBasedCampaigns/DonationBasedCampaigns";
export default function Swibc() {
const sidebar = useDisclosure();
const integrations = useDisclosure();
// Create campaign drawer hooks
const { isOpen, onOpen, onClose } = useDisclosure();
const btnRef = React.useRef();
let { path, url } = useRouteMatch();
const { toggleColorMode: toggleMode } = useColorMode();
const SwitchIcon = useColorModeValue(FaMoon, FaSun);
const NavItem = (props) => {
const { icon, children, ...rest } = props;
return (
<Flex
align="center"
px="4"
pl="4"
py="3"
cursor="pointer"
color={useColorModeValue("inherit", "gray.400")}
_hover={{
bg: useColorModeValue("gray.100", "gray.900"),
color: useColorModeValue("gray.900", "gray.200"),
}}
role="group"
fontWeight="semibold"
transition=".15s ease"
{...rest}
>
{icon && (
<Icon
mr="2"
boxSize="4"
as={icon}
/>
)}
{children}
</Flex>
);
};
const SidebarContent = (props) => (
<Box
as="nav"
pos="fixed"
top="0"
left="0"
zIndex="sticky"
h="full"
pb="10"
overflowX="hidden"
overflowY="auto"
bg={useColorModeValue("white", "gray.800")}
borderColor={useColorModeValue("inherit", "gray.700")}
borderRightWidth="1px"
w="60"
{...props}
>
<Flex px="4" py="5" align="center">
<Text
fontSize="2xl"
ml="2"
color={useColorModeValue("brand.500", "white")}
fontWeight="semibold"
>
cffp
</Text>
</Flex>
<Flex
direction="column"
as="nav"
fontSize="sm"
color="gray.600"
aria-label="Main Navigation"
>
<NavItem icon={MdHome}>Home</NavItem>
<NavItem icon={FaRss}>Articles</NavItem>
<NavItem icon={HiCollection}>Collections</NavItem>
<NavItem icon={FaClipboardCheck}>Checklists</NavItem>
<NavItem icon={HiCode} onClick={integrations.onToggle}>
Integrations
<Icon
as={MdKeyboardArrowRight}
ml="auto"
transform={integrations.isOpen && "rotate(90deg)"}
/>
</NavItem>
<Collapse in={integrations.isOpen}>
<NavItem pl="12" py="2">
Shopify
</NavItem>
<NavItem pl="12" py="2">
Slack
</NavItem>
<NavItem pl="12" py="2">
Zapier
</NavItem>
</Collapse>
<NavItem icon={AiFillGift}>Changelog</NavItem>
<NavItem icon={BsGearFill}>Settings</NavItem>
</Flex>
</Box>
);
return (
<>
<Box
as="section"
bg={useColorModeValue("gray.50", "gray.700")}
minH="100vh"
>
<SidebarContent display={{ base: "none", md: "unset" }} />
<Drawer
isOpen={sidebar.isOpen}
onClose={sidebar.onClose}
placement="left"
>
<DrawerOverlay />
<DrawerContent>
<SidebarContent w="full" borderRight="none" />
</DrawerContent>
</Drawer>
<Box ml={{ base: 0, md: 60 }} transition=".3s ease">
<Flex
as="header"
align="center"
justify="space-between"
w="full"
px="4"
bg={useColorModeValue("white", "gray.800")}
borderBottomWidth="1px"
borderColor={useColorModeValue("inherit", "gray.700")}
h="14"
>
<IconButton
aria-label="Menu"
display={{ base: "inline-flex", md: "none" }}
onClick={sidebar.onOpen}
icon={<FiMenu />}
size="sm"
/>
<InputGroup w="96" display={{ base: "none", md: "flex" }}>
<InputLeftElement color="gray.500" children={<FiSearch />} />
<Input placeholder="Search for articles..." />
</InputGroup>
<Flex align="center">
<Button
colorScheme="brand"
size="sm"
mr={[1,1,3]}
onClick={onOpen}
ref={btnRef}
>
Create <AddIcon ml={[1,1,2]} />
</Button>
// MODAL
<DialogModal />
<Avatar
mr="4"
size="sm"
name="anubra266"
src="https://avatars.githubusercontent.com/u/30869823?v=4"
cursor="pointer"
/>
<Icon mr={4} ml={4} color="gray.500" as={SwitchIcon} cursor="pointer" onClick={toggleMode}/>
</Flex>
</Flex>
</>
);
}
The DialogModal File :
import React from 'react';
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
Button,
Lorem,
useDisclosure
} from "#chakra-ui/react"
const DialogModal = () => {
const { isOpen, onOpen, onClose } = useDisclosure()
return (
<div>
<Button onClick={onOpen}>Open Modal</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
<Lorem count={2} />
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Close
</Button>
<Button variant="ghost">Secondary Action</Button>
</ModalFooter>
</ModalContent>
</Modal>
</div>
)
}
export default DialogModal;
In my case, I was not wrapping the whole component with ChakraProvider because of which the Modal was opening in some weird way.
<ChakraProvider>{...your_component}</ChakraProvider>
The issue went away when I removed Lorem Tag from the modal.
const DialogModal = () => {
const { isOpen, onOpen, onClose } = useDisclosure()
return (
<div>
<Button onClick={onOpen}>Open Modal</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Modal Title</ModalHeader>
<ModalCloseButton />
<ModalBody>
{/* <Lorem count={2} /> */}
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Close
</Button>
<Button variant="ghost">Secondary Action</Button>
</ModalFooter>
</ModalContent>
</Modal>
</div>
)
}

React Modal Submit Form

I'm trying to print out a simple buttton clicked text whenever the submit button is click on my reactstrap modal and somehow my code doesn't do anything, not sure what I have wrong.
I have attached a picture for better visualisation , I'm using reactstrap Modal.
import React, { useState } from "react";
import { Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import Button from "./Button";
// NOTICE
// Modal is brought in with it's own trigger, so import the component where you want the trigger to be.
const ModalComponent = (props) => {
const {
buttonText,
title,
actionButtonText,
cancelButtonText,
children,
className,
} = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
const alertshow = () => {
alert("button clicked");
};
const closeBtn = (
<button className="close" onClick={toggle}>
×
</button>
);
return (
<div>
<a className="btn_link" onClick={toggle}>
{buttonText}
</a>
<form onSubmit={alertshow}>
<Modal isOpen={modal} toggle={toggle} className={className}>
<ModalHeader className=" border-0" toggle={toggle} close={closeBtn}>
{title}
</ModalHeader>
<ModalBody className="text-left border-0">
<p className="modal-label">Please enter your email address</p>
{children}
</ModalBody>
<ModalFooter className="modal-footer border-0">
<Button className="btn_secondary modal-btn" onClick={toggle}>
{cancelButtonText}
</Button>{" "}
<input
className="btn btn_primary modal-btn"
type="submit"
value={actionButtonText}
/>
</ModalFooter>
</Modal>
</form>
</div>
);
};
export default ModalComponent;
Its happening form should be part of modal not modal should be part of form. This is why its not referencing onSubmit. You need to do this:
<Modal isOpen={modal} toggle={toggle} className={className}>
<form onSubmit={alertshow}>
...rest all content
</Form>
</Modal>
Here is full code:
import React, { useState } from "react";
import "./styles.css";
import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from "reactstrap";
// NOTICE
// Modal is brought in with it's own trigger, so import the component where you want the trigger to be.
const ModalComponent = (props) => {
const {
buttonText,
title,
actionButtonText,
cancelButtonText,
children,
className
} = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
const alertshow = () => {
alert("button clicked");
};
const closeBtn = (
<button className="close" onClick={toggle}>
×
</button>
);
return (
<div>
<div onClick={toggle}>{buttonText}</div>
<Modal isOpen={modal} toggle={toggle} className={className}>
<form onSubmit={alertshow}>
<ModalHeader className=" border-0" toggle={toggle} close={closeBtn}>
{title}
</ModalHeader>
<ModalBody className="text-left border-0">
<p className="modal-label">Please enter your email address</p>
{children}
</ModalBody>
<ModalFooter className="modal-footer border-0">
<Button className="btn_secondary modal-btn" onClick={toggle}>
{cancelButtonText}
</Button>{" "}
<input
className="btn btn_primary modal-btn"
type="submit"
value={actionButtonText}
/>
</ModalFooter>
</form>
</Modal>
</div>
);
};
export default function App() {
return (
<div className="App">
<ModalComponent
title="Hello"
cancelButtonText="Cancel"
actionButtonText="Submit"
buttonText="testing"
/>
</div>
);
}
Here is the demo: https://codesandbox.io/s/fervent-bash-51lxe?file=/src/App.js:0-1826
Accepted answer doesn't work when Modal is scrollable.
Here is how to resolve the issue:
<Modal show={ show } onHide={ onClose }
scrollable={ true }
onSubmit={ handleSubmit(onSave) }
dialogAs={ FormWrappedModal }>
<Modal.Header closeButton>
<Modal.Title>some title</Modal.Title>
</Modal.Header>
<Modal.Body>some body</Modal.Body>
<Modal.Footer>some body</Modal.Footer>
</Modal>
We need to introduce custom component FormWrappedModal for that purpose:
const FormWrappedModal = ( props: any)=>{
return (
<form onSubmit={ props.onSubmit }>
<Modal.Dialog { ...props } />
</form>
);
};

Button click won't showing the conditional card in the content material UI

Here is my code.
My goal is: when I click on Login button, content will show the Login card and when I click on Register button content will show the Register card.
As for my primary test, I used the following code:
import React,{useState} from 'react'
const Login=()=>{
return(
<form>
<label>Username:</label>
<input type="text" value="username"/>
<label>Password:</label>
<input type="password" value="password"/>
<button>Submit</button>
</form>
)
}
const Register=()=>{
return(
<form>
<label>Name:</label>
<input type="text" value="name"/>
<label>Username:</label>
<input type="text" value="username"/>
<label>Password:</label>
<input type="password" value="password"/>
<button>Register</button>
</form>
)
}
export default function App() {
const [click,setClick]=useState(false)
const handleClick=()=>{
setClick(true)
}
return (
<div>
<button onClick={handleClick}>Login</button>
{click?<Login/>:<Register/>}
</div>
)
}
And it works. In this way I tried to render functionalities in different components. It seems like not working. What am I missing here?
The following corrections will help you:-
You need to make App component responsible for maintaining click state and then pass only handler (setClick) to AppBar and only state (click) to Content.
import React, { useState } from "react";
import Login from "./Login";
import Register from "./Register";
import { makeStyles } from "#material-ui/core/styles";
import AppBar from "#material-ui/core/AppBar";
import Toolbar from "#material-ui/core/Toolbar";
import Typography from "#material-ui/core/Typography";
import Button from "#material-ui/core/Button";
import IconButton from "#material-ui/core/IconButton";
import MenuIcon from "#material-ui/icons/Menu";
import { Grid } from "#material-ui/core";
const useStyles = makeStyles(theme => ({
root: {
flexGrow: 1
},
menuButton: {
marginRight: theme.spacing(2)
},
title: {
flexGrow: 1
}
}));
function Appbar({ handleClick }) {
const classes = useStyles();
return (
<div className={classes.root}>
<AppBar position="static">
<Toolbar>
<IconButton
edge="start"
className={classes.menuButton}
color="inherit"
aria-label="menu"
>
<MenuIcon />
</IconButton>
<Typography variant="h6" className={classes.title}>
ReactApp
</Typography>
<Button color="inherit" onClick={()=>handleClick(true)}>
Login
</Button>
<Button color="inherit" onClick={()=>handleClick(false)}>
Register
</Button>
</Toolbar>
</AppBar>
</div>
);
}
function Content({ click }) {
const classes = useStyles();
return (
<div className={classes.root}>
<Grid container style={{ padding: 80 }} item>
<Grid xs={false} sm={4} />
<Grid xs={12} sm={8} />
{click ? (
<Login onClick={handleClick} />
) : (
<Register onClick={handleClick} />
)}
<Grid />
<Grid xs={false} sm={2} />
</Grid>
</div>
);
}
export default function App() {
const [click, setClick] = useState(true);
const handleClick = (value) => {
setClick(value);
};
return (
<div>
<Appbar handleClick={handleClick} />
<Content click={click} />
</div>
);
}

react is not firing form onSubmit function

I'm trying to submit form onSubmitbut its not firing the this.commentSubmit function, if i take <form></form> out, use <Button onSubmit> function it works however i need the form wrapped around the Textfield for the backend to read the req.body.comment_body to work.
Comment.js
import React from "react";
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
const Comment = (props) => (
<form onSubmit={props.onSubmit}>
<TextField
type="text"
id="outlined-multiline-static"
label="Write A Comment"
multiline
name="comment_body"
value={props.commentBody}
rows="10"
fullWidth
margin="normal"
variant="outlined"
onChange={props.commentChange}
/>
<Button type="submit" variant="outlined" component="span" color="primary">
Post A Comment
</Button>
</form>
)
export default Comment;
Image Container Component
import React from "react";
import Button from '#material-ui/core/Button';
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
import Divider from '#material-ui/core/Divider';
import Image from './Image';
import Axios from '../Axios';
import moment from 'moment';
import Comment from './Comment';
class ImageContainer extends React.Component{
state = {
isComment: false,
comment_body: ""
}
handleCommentChange = (e) => {
this.setState({
comment_body: e.target.value
})
}
writeComment = (id) => {
this.setState({
isComment: this.state.isComment ? '' : id // check if you state is filled to toggle on/off comment
})
}
commentSubmit = (e) => {
e.preventDefault();
console.log(this.state.comment_body); // doesn't get console.log
Axios.post('/images/newComment', this.state.comment_body).then( (response )=> {
const newComment = { ...response.data};
console.log(newComment);
this.setState({
comment_body: ''
})
})
}
render(){
const { img, deleteImg } = this.props
return(
<Grid item sm={12} md={12} style={{ margin: '30px 0px'}}>
<Paper style={{padding:'20px 20px'}}>
{/* // empty image_title */}
<Typography style={{ padding: '30px 5px', letterSpacing:'8px', textTransform:'uppercase'}} variant="h4" align="center">{img.image_title}</Typography>
<Divider style={{ width: '150px', margin:'10px auto', backgroundColor:'#000000'}} variant="middle" />
<Image image_url={img.img_url} />
<Typography variant="h6" align="center">{img.user.username}</Typography>
<Typography variant="h6" align="center">{moment(img.created_at).calendar()}</Typography>
<Button onClick ={() => this.writeComment(img.id)} variant="outlined" component="span" color="primary">
{this.state.isComment === img.id ? "Close" : "Write A Comment"}
</Button>
{/* here were prevent comments being selected for all items in the array, renders the comment form you clicked on. */}
{this.state.isComment === img.id ?
<Comment onSubmit={this.commentSubmit}
commentBody={this.state.comment_body }
commentChange={this.handleCommentChange}/>
: null}
{/* hide delete button when user enters comment */}
{!this.state.isComment ? <Button style={{margin: '0px 20px'}} onClick={deleteImg} variant="outlined" component="span" color="primary">
Delete
</Button> : null}
</Paper>
</Grid>
)
}
}
export default ImageContainer
Alternatively this works but i don't think the back end reads the comment_body value
import React from "react";
import TextField from '#material-ui/core/TextField';
import Button from '#material-ui/core/Button';
const Comment = (props) => {
// <form onSubmit={props.onSubmit}>
return(
<div>
<TextField
type="text"
id="outlined-multiline-static"
label="Write A Comment"
multiline
name="comment_body"
value={props.commentBody}
rows="10"
fullWidth
margin="normal"
variant="outlined"
onChange={props.commentChange}
/>
<Button onClick={props.onSubmit} type="submit" variant="outlined" component="span" color="primary">
Post A Comment
</Button>
</div>
);
// </form>
}
export default Comment;
backend
router.post('/newComment', async (req, res) => {
const comment = new Comment({
comment_body: req.body.comment_body,
user_id: req.user.id
})
comment.save().then( (comment) => {
return res.status(200).json(comment);
})
})
The problem lies with <Button> from Material-ui not being an actual button but rather a combination of a <span>. So if you have a type="submit" the form doesn't do anything.
If you change your material-ui <Button> to a native <button> it works as expected.
Here's an example: https://codesandbox.io/embed/56615445-fj6sc

Resources