Home > other >  why is useEffect running on first render?
why is useEffect running on first render?

Time:12-17

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}>
      &times;
    </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');
},[]);
  • Related