when state is changed, ckeditor5 is rendered in duplicate in react - javascript

currently, i'm trying to create on/Off function to appear or disappear Ckeditor5
below my code
import { Box, Button, styled, Typography } from "#mui/material";
import React from "react";
import { CKEditor } from "#ckeditor/ckeditor5-react";
import ClassicEditor from "#ckeditor/ckeditor5-build-classic";
const Description = ({ description }) => {
const [isEdit, setIsEdit] = React.useState(false);
const handlerOnOff = () => {
setIsEdit((prev) => !prev);
};
return (
<Root>
<Box>
<Typography component="span">Description</Typography>
<Button onClick={handlerOnOff}>Edit</Button>
</Box>
<Box>
{isEdit ? (
<div>
<CKEditor
config={{
toolbar: [
"heading",
"|",
"bold",
"italic",
"bulletedList",
"numberedList",
"blockQuote"
]
}}
data={description}
editor={ClassicEditor}
/>
</div>
) : (
<>{description}</>
)}
</Box>
</Root>
);
};
const Root = styled("div")(({ theme }) => ({
marginBottom: "60px",
"& .ck-content": {
minHeight: "200px"
}
}));
export default Description;
and codesandbox
https://codesandbox.io/embed/suspicious-mahavira-eoeip1?fontsize=14&hidenavigation=1&theme=dark
when click button named Edit and changed true of state name isEdit, Ckeditor is rendered in duplicate

Related

Warning: Each child in a list should have a unique "key" prop. how to fix this?

Ive been using this project with out a problem and now all of a sudden I keep getting this error and it won't show my notes when I click on the my notes section. What do I have to do for it to go away. The backend is up and running and I can see the static data but it wont show on the app
import { makeStyles } from '#mui/styles'
import React from 'react'
import { Drawer } from '#mui/material'
import { Typography } from '#mui/material'
import List from '#mui/material/List'
import ListItem from '#mui/material/ListItem'
import ListItemIcon from '#mui/material/ListItemIcon'
import ListItemText from '#mui/material/ListItemText'
import { AddCircleOutlineOutlined, SubjectOutlined } from '#mui/icons-material'
import { useHistory, useLocation } from 'react-router-dom'
import AppBar from '#mui/material/AppBar'
import Toolbar from '#mui/material/Toolbar'
import { format } from 'date-fns'
import { red } from '#mui/material/colors'
const drawerWidth = 240 // 500 - subtract this number from
const useStyles = makeStyles((theme) => {
return{
page: {
background: '#E5E4E2',
width: '100%',
padding: theme.spacing(3)
},
drawer: {
width: drawerWidth
},
drawerPaper: {
width: drawerWidth
},
root: {
display: 'flex' //places the drawer side by side with the page content
},
active: {
background: '#E5E4E2'
},
// title:{
// padding: theme.spacing(13),
// alignItems: 'center'
// },
}})
export default function Layout({ children }) {
const classes = useStyles()
const history = useHistory()
const location = useLocation()
const menuItems = [
{
text: 'My Projects',
icon: <SubjectOutlined color="secondary" />,
path: '/'
},
{
text: 'Create Project',
icon: <AddCircleOutlineOutlined color="secondary" />,
path: '/create'
}
]
return (
<div className={classes.root}>
{/* side drawer */}
<Drawer
className={classes.drawer}
variant='permanent' //Lets MUI know we want it on the page permanently
anchor="left" // position of drawer
classes={{ paper: classes.drawerPaper}}
>
<div>
<Typography variant="h5" sx={{textAlign: 'center'}}>
Projects
</Typography>
</div>
{/* List / Links */}
<List>
{menuItems.map(item => (
<div className={location.pathname == item.path ? classes.active : null}>
<ListItem key={item.text} button onClick={() => history.push(item.path)}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.text} />
</ListItem>
</div>
))}
</List>
</Drawer>
<div className={classes.page}>
<div className={classes.toolbar}></div>
{children}
</div>
</div>
)
}
enter image description here
Updated
I'm sorry, of course, you should just move key to the parent div. I didn't notice it. Chris who answered in the comments is right and my answer was not needed. I rewrote the answer.
To have an unique key use index in map or like you did item.text if text is unique for each element in map.
menuItems.map((item,index) =>
The idea is that map has to contain unique key for each element.
In result we have:
<div key={item.text} className={location.pathname == item.path ? classes.active : null}>
or
<div key={index} className={location.pathname == item.path ? classes.active : null}>
And you need to remove key from the List.
Hope this helps! Regards,

material-ui backdrop -- fails with invalid hook call

I have been trying to use material ui backdrop element in my code. I am referring to this example: https://mui.com/components/backdrop/#example
As soon as I introduce this code into my component, it fails with error message as below.
Unhandled Runtime Error Error: Invalid hook call. Hooks can only be
called inside of the body of a function component. This could happen
for one of the following reasons:
You might have mismatching versions of React and the renderer (such as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug
and fix this problem.
My code is as below.
import React, { useState } from 'react'
import { makeStyles } from '#material-ui/core/styles'
import { Box,Typography } from '#material-ui/core'
import CategoryCard from '../shop-categories/category-card'
import { useSelector } from 'react-redux';
//import NavigateBeforeIcon from '#material-ui/icons/NavigateBefore';
//import ProductsInCategory from '../../../pages/shops/product-in-category';
import {useRouter} from 'next/router'
import Backdrop from '#mui/material/Backdrop'
import CircularProgress from '#mui/material/CircularProgress';
import { withStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
heading : {
fontFamily: 'Roboto',
fontSize: 14,
fontStyle: 'normal',
fontWeight: 700,
lineHeight: 1,
color: props => props.pColor
}
})
export default function CategoryGrid(props) {
const { categories, shopId, title} = props;
const shopColors = useSelector(state => state.main.currentShop)
const classes = useStyles(shopColors);
const router = useRouter()
const [open, setOpen] = React.useState(false);
const handleClose = () => {
setOpen(false);
};
const gotoSubCategories = (shopId, id,cat_Name) => {
setOpen(true)
router.push(`/shops/shop-sub-categories?shop=${shopId}&category=${id}&categoryName=${cat_Name}`)
}
return (
<>
<div>
<Backdrop sx={{color: '#fff', zIndex: (theme) => theme.zIndex.drawer +1}}
open={open}
onClick={handleClose}
>
<CircularProgress color='inherit' />
</Backdrop>
</div>
<Typography variant="body2" style={{ fontWeight: 'bold' }}
className={classes.heading}>
{title}
</Typography>
<Box display="flex" mb={2} mx={1} flexDirection="column">
<Box display="flex" fontWeight='fontWeightBold' width={1/2} mb={1}>
</Box>
<Box display="flex" flexWrap="wrap">
{
categories.map((category, index) => {
return <CategoryCard key={index}
name={category.name}
onClick={() => gotoSubCategories(shopId, category.id,category.name)}
imageURL={category.url}
shopId={shopId} callParent={props.callParent}
/>
})
}
</Box>
</Box>
</>
)
}
If I remove out this portion, then it works fine.
<div>
<Backdrop sx={{color: '#fff', zIndex: (theme) => theme.zIndex.drawer +1}}
open={open}
onClick={handleClose}
>
<CircularProgress color='inherit' />
</Backdrop>
</div>
How to fix this?

Converting class to function React Error invalid hook call

I have been converting my class components to functions but I'm stuck on this hook error to do with my export default. I'm sure it's something simple, but I can't find the answer I'm looking for.
This is the code causing the error:
import React from 'react'
import {AppBar, Toolbar, Button, Typography, makeStyles} from '#material-ui/core'
import { connect } from 'react-redux'
import { Link } from 'react-router-dom'
import Menu from './Menu'
const useStyles = makeStyles((theme) => ({
header: {
backgroundColor: "#1d3834",
},
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
}))
function Header(props) {
const classes = useStyles()
const renderContent = () => {
switch (props.auth) {
case null:
return
case false:
return (
<Button color="inherit" href="/signin">Sign In</Button>
)
default:
return (
<Button color="inherit" href="/api/logout">Sign Out</Button>
)
}
}
return(
<div className={classes.root}>
<AppBar position="static" className={classes.header}>
<Toolbar>
<Menu/>
<Typography variant="h6" className={classes.title} >
<Link
to={props.auth ? '/items' : '/'}
className="left brand-logo"
>
</Link>
</Typography>
{renderContent()}
</Toolbar>
</AppBar>
</div>
);
}
function mapStateToProps({auth}) {
return{ auth }
}
export default connect(mapStateToProps)(makeStyles(useStyles) (Header))
I'm hoping someone has ran into a similar issue before and would be able to give me some feedback, Thanks :)
The main issue is how you export your component. Try instead as the following:
export default connect(mapStateToProps)(Header)
You don't really need the makeStyles(useStyles) part there.
+1 suggestion - not related to the question:
This suggestion is not related to the question itself, it's just a small improvement how I like to organize makeStyles stuff in my code repository with Material-UI.
Usually I create a styles.tsx which would look like in your case as the following, placed next to your component file:
import { makeStyles } from "#material-ui/core"
const useStyles = makeStyles((theme) => ({
header: {
backgroundColor: "#1d3834",
},
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
}))
export default useStyles
Then import in the component as the following:
import useStyles from "./styles"
And the usage similarly as in your component:
function Header(props) {
const classes = useStyles()
// ... rest of your component
}

How to add styles to an unknown child in React with Material-UI?

The below function is going to be run on a loop. I want to add styles to the icon which I want to pass as an argument to the function.
The icon is a going to be an unknown React Material-UI Icon component.
const renderStyledCard = (lightMode, heading, num, icon) => {
const classes = lightMode ? useLightCardStyles(): useDarkCardStyles();
return (
<Card className={classes.root}>
<CardContent>
<Typography variant="h4" component="h4" className={classes.textColor}>
{heading}
</Typography>
<div className={classes.content}>
<Typography variant="h4" component="h4" className={classes.textColor}>
{num}
</Typography>
{icon}
// Ex. <VpnKey className={[classes.icon, classes.textColor]} />
// Ex. <AccountCircle className={[classes.icon, classes.textColor]} />
{icon}
</div>
</CardContent>
</Card>
);
};
Loop execution is going to be like -
return [
{light: true,
heading: 'Accounts',
num: 100,
icon: <AccountCircle />
},
...theRest
].map(ele => renderStyledCard(...ele))
The loop code could be wrong I just wrote it here as an example to show how I wanted to execute it. Is there a better way? Any help would be awesome.
Some notice points:
add {} like ({ light, heading, num, icon }) to list the props
props lightMode not match list attribute light, need to change one of them
use Material-UI nesting selector & svg to customize the icon style from its parent div
Full code sample:
import React from "react";
import "./styles.css";
import GetApp from "#material-ui/icons/GetApp";
import AccountCircle from "#material-ui/icons/AccountCircle";
import { Card, CardContent, Typography, makeStyles } from "#material-ui/core";
const useLightCardStyles = makeStyles(theme => ({
root: {},
content: {
"& svg": {
color: "red"
}
}
}));
const useDarkCardStyles = makeStyles(theme => ({}));
const data = [
{ light: true, heading: "Accounts", num: 100, icon: <AccountCircle /> },
{ light: true, heading: "Accounts", num: 100, icon: <GetApp /> }
];
const StyledCard = ({ light, heading, num, icon }) => {
const lightCardClasses = useLightCardStyles();
const darkCardClasses = useDarkCardStyles();
const classes = light ? lightCardClasses : darkCardClasses;
return (
<Card className={classes.root}>
<CardContent>
<Typography variant="h4" component="h4" className={classes.textColor}>
{heading}
</Typography>
<div className={classes.content}>
<Typography variant="h4" component="h4" className={classes.textColor}>
{num}
</Typography>
{icon}
</div>
</CardContent>
</Card>
);
};
export default function App() {
return (
<div className="App">
{data.map(props => (
<StyledCard {...props} />
))}
</div>
);
}
I think this should work:
const renderStyledCard = (lightMode, heading, num, icon) => {
const classes = lightMode ? useLightCardStyles(): useDarkCardStyles();
icon.style.color = "red";
return(/*....*/)
}
Try console.log(icon.style)

How do I delete a card component using id from a data object?

I have built a Trello clone using ReactJS, where I have 4 columns called TODO, DOING, DONE and REJECTED, where I can add a card to any column.
In a file I am trying to map over card component and rendering properties from defined dummy data.
What I want to do?
I want to delete a specific card when it is clicked using the card id in some way.
What is the problem?
I do not understand how do I delete an entire card object when it matches a certain id.
My TaskboardList.js component :
import React from "react";
import TaskboardCard from "./TaskboardCard";
import TaskboardActionButton from "./TaskboardActionButton";
import { Droppable } from "react-beautiful-dnd";
const TaskboardList = ({ title, cards, listID }) => {
return (
<Droppable droppableId={String(listID)}>
{provided => (
<div
className="taskboardlist_container"
{...provided.droppableProps}
ref={provided.innerRef}
style={styles.container}
>
<div className="sub-heading">{title}</div>
{cards.map((card, index) => (
<TaskboardCard
key={card.id}
index={index}
text={card.text}
id={card.id}
/>
))}
<TaskboardActionButton listID={listID} />
{provided.placeholder}
</div>
)}
</Droppable>
);
};
const styles = {
container: {
backgroundColor: "#eee",
width: 300,
padding: "0.5rem",
marginRight: "1rem",
height: "100%"
}
};
export default TaskboardList;
My TaskboardCard.js component
import React from "react";
import Card from "#material-ui/core/Card";
import Typography from "#material-ui/core/Typography";
import CardContent from "#material-ui/core/CardContent";
import { Draggable } from "react-beautiful-dnd";
const TaskboardCard = ({ text, id, index, sample }) => {
return (
<Draggable draggableId={String(id)} index={index}>
{provided => (
<div
className="taskboard_container"
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<Card>
<CardContent>
<Typography style={{ fontSize: "1.5rem" }} gutterBottom>
{text}
</Typography>
</CardContent>
</Card>
</div>
)}
</Draggable>
);
};
export default TaskboardCard;
For further reference to more files, I am attaching my GitHub link. Please consider visiting.
Any help would be much appreciated.
https://github.com/abhinav-anshul/consensolabs
And here is the link for a live demo https://consensolab.abhinavanshul.com/
// src/actions/index.js
export const CONSTANTS = {
ADD_CARD: "ADD_CARD",
ADD_LIST: "ADD_LIST",
DRAG_HAPPENED: "DRAG_HAPPENED",
DELETE_CARD: "DELETE_CARD"
};
// src/actions/cardActions.js
export const deleteCard = cardId => ({
type: CONSTANTS.DELETE_CARD,
payload: { cardId }
});
// src/reducers/listReducers.js
const listReducer = (state = initialState, action) => {
// ...
case CONSTANTS.DELETE_CARD: {
return {
...state,
cards: state.cards.filter(({id}) => id !== action.payload.cardId)
}
}
Then from your delete button, you just need to call dispatch(deleteCard(cardId))
Edit: I've updated your code sandbox to implement this https://codesandbox.io/s/stupefied-golick-7z78k

Categories

Resources