I have a MERN react component that is going to show a toast to my user after they create a new group.
Here is my useEffect below
useEffect(() => {
toast(
<Fragment>
New Group Created
</Fragment>
);
}, [successCreate]);
I only want this useEffect to run AFTER my user creates a new group.
It currently runs on first render, and after my user clicks the modal(child) then triggers the successCreate from redux(just creates a new group).
How can I make useEffect run only when successCreate is called.. NOT on first render AND successCreate
Here is my component
import React, { Fragment, useState, useEffect, useContext } from 'react';
import WizardInput from '../auth/wizard/WizardInput';
import {useDispatch, useSelector} from 'react-redux';
import {
Button,
Card,
CardBody,
Form,
Label,
Input,
Media,
Modal,
ModalBody,
ModalHeader
} from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import Select from 'react-select';
import { toast } from 'react-toastify';
import makeAnimated from 'react-select/animated';
import {listGroups, createGroup} from '../../actions/index';
//import { isIterableArray } from '../../helpers/utils';
import { CsvUploadContext } from '../../context/Context';
import chroma from 'chroma'
const StepOneForm = ({ register, errors, watch}) => {
const { upload, setUpload } = useContext(CsvUploadContext);
//const { handleInputChange } = useContext(CsvUploadContext);
const [ createGroupModal, setCreateGroupModal ] = useState(false)
const [newGroup, setNewGroup] = useState({
title: ''
})
const dispatch = useDispatch();
const groups = useSelector(state => state.groups)
const groupCreate = useSelector((state) => state.groupCreate)
const {success: successCreate} = groupCreate
const animatedComponents = makeAnimated();
useEffect(() => {
dispatch(listGroups())
}, [successCreate])
useEffect(() => {
toast(
<Fragment>
New Group Created
</Fragment>
);
}, [successCreate]);
const customStyles = {
control: (base, state) => ({
...base,
background: "light",
// match with the menu
borderRadius: state.isFocused ? "3px 3px 0 0" : 3,
// Overwrittes the different states of border
borderColor: state.isFocused ? "primary" : "light",
// Removes weird border around container
boxShadow: state.isFocused ? null : null,
"&:hover": {
// Overwrittes the different states of border
borderColor: state.isFocused ? "blue" : "#2c7be5"
}
}),
menu: base => ({
...base,
// override border radius to match the box
borderRadius: 0,
// kill the gap
marginTop: 0
}),
menuList: base => ({
...base,
// kill the white space on first and last option
padding: 0,
color: 'f9fafd'
}),
option: (styles, { data, isDisabled, isFocused, isSelected }) => {
const color = chroma(data.color);
return {
...styles,
backgroundColor: isDisabled
? null
: isSelected
? data.color
: isFocused,
color: '232e3c',
};
}
};
const toggle = () => { setCreateGroupModal(!createGroupModal)}
const closeBtn = (
<button className="close font-weight-normal" onClick={toggle}>
×
</button>
);
const handleSubmit = (e) => {
e.preventDefault()
dispatch(createGroup(newGroup))
setCreateGroupModal(false)
};
console.log(upload?.group)
const handleChange = e => {
setNewGroup({...newGroup, [e.target.name]: e.target.value})
}
return (
<Fragment>
<Media className="flex-center pb-3 d-block d-md-flex text-center mb-2">
<Media body className="ml-md-4">
</Media>
</Media>
<h4 className="mb-1 text-center">Choose Groups</h4>
<p className=" text-center fs-0">These groups will contain your contacts after import</p>
<Select
name="group"
required={true}
className="mb-3"
styles={customStyles}
components={animatedComponents}
innerRef={register({
required: true
})}
closeMenuOnSelect={true}
options={groups}
getOptionLabel={({title}) => title}
getOptionValue={({_id}) => _id}
onChange={(_id) => setUpload({...upload, group: _id})}
isMulti
placeholder="select group"
isSearchable={true}
errors={errors}
/>
<Button color="light" onClick={(() => setCreateGroupModal(true))} className="rounded-capsule shadow-none fs--1 ml- mb-0" >
<FontAwesomeIcon icon="user-plus" />
{` or create a new group`}
</Button>
<Modal isOpen={createGroupModal} centered toggle={() => setCreateGroupModal(!createGroupModal)}>
<ModalHeader toggle={toggle} className="bg-light d-flex flex-between-center border-bottom-0" close={closeBtn}>
Let's give the group a name
</ModalHeader>
<ModalBody className="p-0">
<Card>
<CardBody className="fs--1 font-weight-normal p-4">
<Card>
<CardBody className="fs--1 font-weight-normal p-4">
<Form onSubmit={handleSubmit}>
<Label for="title">Group Name:</Label>
<Input value={newGroup.title.value} onChange={handleChange} className="mb-3" name="title" id="title"/>
<Button block onClick={handleSubmit} color="primary" className="mb-3">Save</Button>
</Form>
</CardBody>
</Card>
<Button block onClick={() => setCreateGroupModal(false)}>close</Button>
</CardBody>
</Card>
</ModalBody>
</Modal>
<WizardInput
type="textarea"
label="or add number manually seperated by comma"
placeholder=" 17209908576, 18165009878, 19138683784"
name="manual-add"
rows="4"
id="manual-add"
innerRef={register({
required: false
})}
errors={errors}
/>
</Fragment>
);
};
export default StepOneForm;
CodePudding user response:
Is successCreate
a boolean?
This would work:
useEffect(() => {
if(!successCreate) return;
toast(
<Fragment>
New Group Created
</Fragment>
);
}, [successCreate]);
useEffect
is always called when the dependencies change - on first render it is guaranteed to be called because there is nothing previous - this is the equivalent to componentDidMount
useEffect(() => {
console.log('mounted');
},[]);