Not apply dynamic class in react js rendering - reactjs

I am applying class on condition based but it is not apply. But when I apply class name static then it is applied successfully.
const styles = theme => ({
labelsuccess: {
"background-color": "#5cb85c"
},
labelprogress: {
"background-color": "#f0ad4e"
}
});
let labelcolor = [
{
status: "In Progress",
class: "classes.labelprogress"
},
{
status: "Completed",
class: "classes.labelsuccess"
}
];
{Developertasklist.map((task, index) => (
<ListItem key={index} divider="true">
<div className={classes.taskwidth}>
<span className={classes.hideelement}>
{
(foundValue = labelcolor.filter(
obj => obj.status === task.status
)[0].class)
}
</span>
<ListItemText
primary={
<React.Fragment>
{task.name} - {task.due_date}
</React.Fragment>
}
secondary={
<React.Fragment>
<Typography
component="span"
className={foundValue}
color="textPrimary"
>
{task.status}
</Typography>
</React.Fragment>
}
/>
</div>
</ListItem>
))}
Why dynamic class does not apply?

set your variable before the return. Not inside.
with arrow functions, you doesn't need use return if you use brackets like this () => ( ... ), but if you want to set variable or calculating, use with curly brackets and return statement. like this;
() => {
const a = 'variable';
return ( <div class={a}>... );
}
try this one.
{Developertasklist.map((task, index) => {
const foundValue = labelcolor.filter(
obj => obj.status === task.status
)[0].class;
return (
<ListItem key={index} divider="true">
<div className={classes.taskwidth}>
<ListItemText
primary={
<React.Fragment>
{task.name} - {task.due_date}
</React.Fragment>
}
secondary={
<React.Fragment>
<Typography
component="span"
className={foundValue}
color="textPrimary"
>
{task.status}
</Typography>
</React.Fragment>
}
/>
</div>
</ListItem>
)}
)}

Related

Warning: Each child in a list should have a unique "key" prop; Check the render method of `Post`

when I click by tag, it works fine, but when I click creators, it just return "No posts".
I check the console, and there's an error says the key in list should be unique. Why this happens? Since searchbytag works, does this mean the render method of 'Post' is fine?
updated code
import axios from 'axios';
const API = axios.create({ baseURL: 'http://localhost:5000' });
API.interceptors.request.use((req) => {
if (localStorage.getItem('profile')) {
req.headers.Authorization = `Bearer
${JSON.parse(localStorage.getItem('profile')).token}`;
}
return req;
});
export const createPost = (newPost) => API.post('/posts', newPost);
const Post = ({ post, setCurrentId }) => {
const user = JSON.parse(localStorage.getItem('profile'));
const [likes, setLikes] = useState(post?.likes);
const dispatch = useDispatch();
const history = useHistory();
const classes = useStyles();
const userId = user?.result?._id;
const hasLikedPost = post.likes.find((like) => like === userId);
const handleLike = async () => {
dispatch(likePost(post._id));
if (hasLikedPost) {
setLikes(post.likes.filter((id) => id !== userId));
} else {
setLikes([...post.likes, userId]);
}
};
const Likes = () => {
if (likes.length > 0) {
return likes.find((like) => like === userId)
? (
<><ThumbUpAltIcon fontSize="small" /> {likes.length > 2 ? `You and ${likes.length - 1} others` : `${likes.length} like${likes.length > 1 ? 's' : ''}`}</>
) : (
<><ThumbUpAltOutlined fontSize="small" /> {likes.length} {likes.length === 1 ? 'Like' : 'Likes'}</>
);
}
return <><ThumbUpAltOutlined fontSize="small" /> Like</>;
};
const openPost = (e) => {
// dispatch(getPost(post._id, history));
history.push(`/posts/${post._id}`);
};
return (
<Card className={classes.card} raised elevation={6}>
<ButtonBase
component="span"
name="test"
className={classes.cardAction}
onClick={openPost}
>
<CardMedia className={classes.media} image={post.selectedFile || 'https://user-images.githubusercontent.com/194400/49531010-48dad180-f8b1-11e8-8d89-1e61320e1d82.png'} title={post.title} />
<div className={classes.overlay}>
<Typography variant="h6">{post.name}</Typography>
<Typography variant="body2">{moment(post.createdAt).fromNow()}</Typography>
</div>
{(user?.result?._id === post?.creator) && (
<div className={classes.overlay2} name="edit">
<Button
onClick={(e) => {
e.stopPropagation();
setCurrentId(post._id);
}}
style={{ color: 'white' }}
size="small"
>
<MoreHorizIcon fontSize="default" />
</Button>
</div>
)}
<div className={classes.details}>
<Typography variant="body2" color="textSecondary" component="h2">{post.tags.map((tag) => `#${tag} `)}</Typography>
</div>
<Typography className={classes.title} gutterBottom variant="h5" component="h2">{post.title}</Typography>
<CardContent>
<Typography variant="body2" color="textSecondary" component="p">{post.message.split(' ').splice(0, 20).join(' ')}...</Typography>
</CardContent>
</ButtonBase>
<CardActions className={classes.cardActions}>
<Button size="small" color="primary" disabled={!user?.result} onClick={handleLike}>
<Likes />
</Button>
{(user?.result?._id === post?.creator) && (
<Button size="small" color="secondary" onClick={() => dispatch(deletePost(post._id))}>
<DeleteIcon fontSize="small" /> Delete
</Button>
)}
</CardActions>
</Card>
);
};
export default Post;
Here's my code
const CreatorOrTag = () => {
const { name } = useParams();
const dispatch = useDispatch();
const { posts, isLoading } = useSelector((state) => state.posts);
const location = useLocation();
useEffect(() => {
if (location.pathname.startsWith('/creators')) {
dispatch(getPostsByCreator({ name: name }));
}
else {
dispatch(getPostsBySearch({ tags: name }));
}
}, []);
if (!posts.length && !isLoading) return 'No posts';
return (
<div>
<Typography variant="h2">{name}</Typography>
<Divider style={{ margin: '20px 0 50px 0' }} />
{isLoading ? <CircularProgress /> : (
<Grid container alignItems="stretch" spacing={3}>
{posts?.map((post) => (
<Grid key={post._id} item xs={12} sm={12} md={6} lg={3}>
<Post post={post} />
</Grid>
))}
</Grid>
)}
</div>
);
};
export default CreatorOrTag;
What this warning indicates is that the value you're providing for key is the same in at least two items of the array. I'd put money on the _id property for at least two of them being null or undefined.

Passing click function from One component to other component

In React material ui i am having two components where i am calling save function on button click, is it right way or not can anyone suggest the better way:
const callback = {};
return (
<>
{!state?.creditCard?.isSaved ? (
<Paper elevation={4} className={classes.paymentContainer}>
<Box className={classes.subPaymentContainer}>
<Typography className={classes.title}>Card Payment</Typography>
<CardPaymentForm
callback={callback}
validationPassed={() => actionsCollection.booking.saveCard(true, state.creditCard.lastFourDigits)}
formType="profileForm"
/>
<div>
<Button
type="submit"
onClick={(e) => callback.saveCard(e)}
value="SAVE CREDIT CARD"
className={classes.button}
/>
<div style={{ display: "flex", marginTop: 20 }}>
<img className={classes.lockIcon} src={lockIconInfo} alt="" />
<Typography className={classes.paymentInfo}>
<Link href="/terms" target={"_blank"}>
Terms of Payment
</Link>
.
</Typography>
</div>
</div>
</Box>
</Paper>
) : (
<div style={{ height: 373 }}>
<CardStored removeCard={removeCard} />
</div>
)}
</>
);
in CardPayementForm below calling the save function below is the code:
const CardPaymentForm = ({ classes, callback, validationPassed, formType, lastFourDigits }) {
useEffect(() => {
callback.saveCard = (e) => {
e.preventDefault();
=
if (validateForm()) {
=
validationPassed();
}
};
});
}
here without callback how to call save function directly in cardpaymentform, Any help please
I'm not sure this will apply to your problem but if you had a component_a
like
const ComponentA = ({handleClick}) => {
return(
<>
<button onClick(e => handleEvent(e))>
Click here
</button>
</>
}
and a component_b
const ComponentB = () => {
const handleClick = (e) => {
// do something with the event from component a
}
return(
<>
<ComponentA handleClick={handleClick}/>
</>
)
}

'Save Palette' button gives a TypeError of 'savePalette' is not a function

My 'NewPaletteForm' is a functional component as I've used react hooks.
So when I click the button 'Save Palette', an error occurs which says 'props.savePalette is not a function'.
ERROR:-
TypeError: props.savePalette is not a function
Code:
'App.js':
class App extends Component {
constructor(props) {
super(props);
this.state = { palettes: seedColors };
this.findPalette = this.findPalette.bind(this);
this.savePalette = this.savePalette.bind(this);
}
findPalette(id) {
return this.state.palettes.find(function (palette) {
return palette.id === id;
});
}
savePalette(newPalette) {
this.setState({ palettes: [...this.state.palettes, newPalette] });
}
render() {
return (
<Switch>
<Route
exact
path='/palette/new'
render={(routeProps) => <NewPaletteForm savePalette={this.savePalette} {...routeProps} />} />
'NewPaletteForm.js' : Functional Component which includes react hooks
function NewPaletteForm() {
const classes = useStyles();
const [open, setOpen] = useState(false);
const [currentColor, setCurrentColor] = useState('teal');
const [colors, setColors] = useState([{ color: 'pink', name: 'pink' }]);
const [newName, setNewName] = useState('');
useEffect(() => {
ValidatorForm.addValidationRule('isColorNameUnique', (value) => {
return colors.every(
({ name }) => name.toLowerCase() !== value.toLowerCase()
);
});
ValidatorForm.addValidationRule('isColorUnique', (value) => {
return colors.every(
({ color }) => color !== currentColor
);
});
})
const handleDrawerOpen = () => {
setOpen(true);
};
const handleDrawerClose = () => {
setOpen(false);
};
function updateCurrentColor(newColor) {
setCurrentColor(newColor.hex);
};
function addNewColor() {
const newColor = {
color: currentColor,
name: newName
}
setColors(oldColors => [...oldColors, newColor]);
setNewName('');
};
function handleChange(evt) {
setNewName(evt.target.value);
}
function handleSubmit(props) {
const newPalette = {
paletteName: 'Test Palette',
colors: colors
}
props.savePalette(newPalette);
props.history.push('/');
}
return (
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
color='default'
className={clsx(classes.appBar, {
[classes.appBarShift]: open,
})}
>
<Toolbar>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={handleDrawerOpen}
edge="start"
className={clsx(classes.menuButton, open && classes.hide)}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap>
Persistent drawer
</Typography>
<Button variant='contained' color='primary' onClick={handleSubmit}>Save Palette</Button>
</Toolbar>
</AppBar>
<Drawer
className={classes.drawer}
variant="persistent"
anchor="left"
open={open}
classes={{
paper: classes.drawerPaper,
}}
>
<div className={classes.drawerHeader}>
<IconButton onClick={handleDrawerClose}>
<ChevronLeftIcon />
</IconButton>
</div>
<Typography variant='h4'>Design Your Palette</Typography>
<div>
<Button variant="contained" color="secondary">
Clear Palette
</Button>
<Button variant="contained" color="primary">
Random Color
</Button>
</div>
<Divider />
<ChromePicker color={currentColor} onChangeComplete={updateCurrentColor} />
<ValidatorForm onSubmit={addNewColor}>
<TextValidator
value={newName}
onChange={handleChange}
validators={['required', 'isColorNameUnique', 'isColorUnique']}
errorMessages={['Enter a color name', 'Color name must be unique', 'Color already used!']}
/>
<Button
variant='contained'
type='submit'
color='primary'
style={{
backgroundColor: currentColor
}}
>
Add Color
</Button>
</ValidatorForm>
</Drawer>
<main
className={clsx(classes.content, {
[classes.contentShift]: open,
})}
>
<div className={classes.drawerHeader} />
{colors.map(color => (
<DraggableColorBox color={color.color} name={color.name} />
))}
</main>
</div>
);
}
Button in the NewPaletteForm Component: (Used Material UI Button component)
<Button variant='contained' color='primary' onClick={handleSubmit}>Save Palette</Button>
You should remove props from function argument. because you are calling handleSubmit on button click so it's getting event as props.
function handleSubmit() {
const newPalette = {
paletteName: 'Test Palette',
color: colors
}
props.savePalette(newPalette);
props.history.push('/');
}
Also add props argument to function NewPaletteForm(props) {

React: How to pass the data from function located on the child component into parent component?

I have a function called handleDelete that contains the id of specific task. I want to pass the value of that function to my parent component because this will be my reference for my prompt component. The prompt component contains the title of the task that's the reason that I want to get the task id.
Parent Component
const Home = ({ history }) => {
const [taskDeleteId, setDaskDeleteId] = useState();
const [showPrompt, setShowPrompt] = useState(false);
return (
<>
<Grid>
<TasksList deleteId={(deleteId) => setDaskDeleteId(deleteId)} />
<PromptComponent showPrompt={showPrompt} taskId={taskIdref} />
</Grid>
</>
);
};
export default Home;
Child Component
const TasksList = ({ taskId, deleteId }) => {
//Function
const handleDelete = (e) => {
deleteId = e.currentTarget.getAttribute('taskId');
setAssignTask(assignTask.filter((task) => task._id !== deleteId));
};
return (
<>
<Container
component='div'
maxWidth='xl'
className={classes.taskContainer}
>
<Container
component='div'
maxWidth='xl'
className={classes.todoContainer}
onDragOver={(e) => onDragOverTask(e)}
onDragLeave={(e) => onDragLeaveTask(e)}
onDrop={(e) => onDropTask(e)}
>
{taskTodo.map((currentTask, index) => {
return (
<Card
variant='outlined'
className={classes.cardTask}
key={index}
style={{ background: '#f3f3f3', marginTop: '1rem' }}
onDragStart={(e) => onDragStartTask(e, currentTask._id)}
draggable
>
<div className={classes.topContent}>
<CardActions
className={
classes[
currentTask.priority === 'High'
? 'checkBoxContainerHigh'
: currentTask.priority === 'Minor'
? 'checkBoxContainerMinor'
: currentTask.priority === 'Low'
? 'checkBoxContainerLow'
: 'checkBoxContainer'
]
}
>
<Checkbox
icon={<CircleUnchecked />}
checkedIcon={<CircleCheckedFilled />}
color='primary'
className={classes.completeAction}
id={currentTask._id}
checked={currentTask.isComplete}
onChange={handleCheckStatus}
/>
</CardActions>
<CardContent className={classes.cardContentTop}>
<Typography variant='h6'>{currentTask.title}</Typography>
<Typography variant='caption' color='textSecondary'>
<EventIcon />
{moment(currentTask.dateDue).format('dddd, Do MMMM')}
</Typography>
</CardContent>
{currentTask.desc && (
<CardActions disableSpacing style={{ marginLeft: 'auto' }}>
<IconButton
className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})}
onClick={handleChange(`todo-panel_${index}`)}
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
)}
</div>
{currentTask.desc && (
<Collapse
in={expanded === `todo-panel_${index}`}
timeout='auto'
unmountOnExit
className={classes.collapsePanel}
color='primary'
>
<CardContent className={classes.descPrevContainer}>
<Typography
variant='body1'
className={classes.text}
dangerouslySetInnerHTML={createMarkup(
textTruncate(currentTask.desc, 50)
)}
></Typography>
</CardContent>
</Collapse>
)}
<CardActions
disableSpacing
className={classes.bottomActionsContainer}
>
<Tooltip title='Delete'>
<IconButton
aria-label='delete'
className={classes.BottomDelete}
taskid={currentTask._id}
onClick={handleDelete}
>
<DeleteIcon />
</IconButton>
</Tooltip>
<Tooltip title='Edit'>
<IconButton
aria-label='edit'
className={classes.BottomEdit}
taskid={currentTask._id}
>
<EditIcon />
</IconButton>
</Tooltip>
</CardActions>
</Card>
);
})}
</Container>
</Container>
</>
);
};
As a previous commenter mentioned, pass a callback down to the Child. Update your parent component as follows
const Home = ({ history }) => {
const [taskDeleteId, setDaskDeleteId] = useState();
const [showPrompt, setShowPrompt] = useState(false);
return (
<>
<Grid>
<TasksList deleteId={taskDeleteId} setDeleteId={setDaskDeleteId} />
<PromptComponent showPrompt={showPrompt} taskId={taskIdref} />
</Grid>
</>
);
};
Then in your child you can call the function passed from the parent to set the state properly.
const TasksList = ({ taskId, deleteId, setDeleteId }) => {
// Function
const handleDelete = (e) => {
setDeleteId(e.currentTarget.getAttribute('taskId'));
...
};
return (...

How to get the key on click event

I have the following react component:
type MobileNavProp = RouteTableProp
export default function MobileNav({routes}: MobileNavProp) {
const classes = useStyles()
const [drawerOpen, setDrawerOpen] = useState<boolean>(false)
const handleOnClickItem = (event: React.MouseEvent<HTMLDivElement>): void => console.log(event.target)
return (
<React.Fragment>
<IconButton
className={classes.icon}
color="inherit"
aria-label="Open navigation"
edge="end"
onClick={() => setDrawerOpen(true)}
>
<MenuRoundedIcon fontSize="large"/>
</IconButton>
<SwipeableDrawer open={drawerOpen}
onClose={() => setDrawerOpen(false)}
onOpen={() => console.log("Drawer is open")}
disableBackdropTransition={!iOS}
anchor="top"
disableDiscovery={iOS}
>
<List subheader={
<ListSubheader component="div" id="logo" className={classes.company}>
<img className={classes.logo} src={logo} alt="databaker-logo"/>
<Typography variant="h6" className={classes.title}>
DATABAKER
</Typography>
</ListSubheader>
}>
{
routes.map((rt, index) => (
<ListItem
divider
key={index}
button
onClick={handleOnClickItem}
>
<ListItemText primary={rt.name}/>
</ListItem>
))
}
</List>
</SwipeableDrawer>
</React.Fragment>
)
}
When the user click on ListItem(the handler function is handleOnClickItem), then it shows me:
<span class="MuiTypography-root MuiListItemText-primary MuiTypography-body1 MuiTypography-displayBlock">ABOUT US</span>
However, I would like to get the clicked index that I have provided:
<ListItem
divider
key={index}...
How to get it?
You can make handleOnClickItem a higher-order function that takes the index as a parameter, and call it:
const makeHandleOnClickItem = (i: number) => (event: React.MouseEvent<HTMLDivElement>) => {
console.log(event.target);
console.log(i);
};
and change
onClick={handleOnClickItem}
to
onClick={makeHandleOnClickItem(index)}

Resources