Home > Back-end >  How to hide a form after submit in react, currently you have to click a toggle button
How to hide a form after submit in react, currently you have to click a toggle button

Time:12-09

Currently I am rendering a list of songs where there is a toggle button I made to render a form to add a song. How can I make it so when that form is submitted it will hide the form without a button click. I attempted to make a useEffect to trigger the function but I couldn't crack it. Thanks in advance.

The list of songs

import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';

import { deleteSong, getSongs, updateSong } from '../../store/song';

import ReactAudioPlayer from 'react-audio-player';
import { useHistory } from 'react-router';
import SongForm from '../AddSongForm';
import EditSongForm from '../EditSongForm';
import SpecificSong from '../SpecificSong';

const SongList = () => {

    const [addShowForm, setAddShowForm] = useState(false);
    // const [editShowForm, setEditShowForm] = useState(false);

    const history = useHistory()
    const dispatch = useDispatch();

    const songsObj = useSelector((state) => state.songState.entries);
    const songs = Object.values(songsObj)

    const user = useSelector((state) => state.session.user);
    const CurrentUserId = user?.id

    const remove = (e) => {
        dispatch(deleteSong(e.target.id));
    }


    const addFormCheck = (e) => {
        if (addShowForm) setAddShowForm(false)
        if (!addShowForm) setAddShowForm(true)
    }
    // const editFormCheck = (e) => {
    //     if (editShowForm) setEditShowForm(false)
    //     if (!editShowForm) setEditShowForm(true)
    // }

    useEffect(() => {
        dispatch(getSongs());
    }, [dispatch]);


    return (
        <div>
            <div>
                <button onClick={addFormCheck}>add a song</button>
                {addShowForm ?
                    <SongForm />
                    : null}
            </div>
            <h1>Song List</h1>
            <ol>
                {songs.map(({ id, songName, songLink, userId }) => (
                    <div>
                        <SpecificSong id={id} songName={songName} songLink={songLink} userId={userId} />
                    </div>
                ))}
            </ol>
        </div>
    );
};
export default SongList;

And the component that is being rendered

import { useState } from "react";
import { useDispatch } from "react-redux";

import { postSong } from "../../store/song";

import { useSelector } from "react-redux";



import Axios from 'axios'

const SongForm = () => {
    const dispatch = useDispatch();

    const [songName, setSongName] = useState("");
    const [songLink, setSongLink] = useState("");
    const [errors, setErrors] = useState([]);

    const [songSelected, setSongSelected] = useState("")

    const reset = () => {
        setSongName("");
        setSongLink("");

    };
    const user = useSelector((state) => state.session.user);
    const userId = user?.id

    let url;

    const handleSubmit = async (e) => {
        e.preventDefault();

        const formData = new FormData()
        formData.append('file', songSelected)
        formData.append('upload_preset', 'd3gthd7l')

        if (songSelected === '') {
            setErrors(['You have to upload an audio file!'])
        }

        Axios.post("https://api.cloudinary.com/v1_1/dyhfkvy6u/video/upload", formData).then(async (response) => {
            if (response.data.url) url = response.data.url
            const newSong = {
                songName,
                songLink: url,
                userId
            };
            const song = await dispatch(postSong(newSong))
                .catch(async (res) => {
                    const data = await res.json()
                    if (data && data.errors) setErrors(data.errors)
                })


        })

        // reset();
    };


    return (
        <div className="inputBox">
            <h1>Add A Song</h1>
            <ul>
                {errors.map((error, idx) => <li className='errors' key={idx}>{error}</li>)}
            </ul>
            <form onSubmit={handleSubmit}>
                <input
                    type="text"
                    onChange={(e) => setSongName(e.target.value)}
                    value={songName}
                    placeholder="Song Name"
                    name="Song Name"
                />
                <input
                    type='file'
                    onChange={(e) => { setSongSelected(e.target.files[0]) }}
                    placeholder="Song Link"
                    name="Audio File"
                />
                <button type="submit">Submit</button>


            </form>
        </div>
    );
};

export default SongForm;

CodePudding user response:

You could pass the setAddShowForm function to the form as a prop and update its state once submitted (Note that you can use && for conditional rendering):

<div>
  <button onClick={addFormCheck}>add a song</button>
  {addShowForm && <SongForm setAddShowForm={setAddShowForm}/>}
</div>

Change your component declaration to

const SongForm = ({ setAddShowForm }) => {

And update the state in the handleSubmit method:

const handleSubmit = async (e) => {
    e.preventDefault();
  
    const formData = new FormData();
    formData.append('file', songSelected);
    formData.append('upload_preset', 'd3gthd7l');
  
    if (songSelected === '') {
      setErrors(['You have to upload an audio file!']);
    }
  
    Axios.post(
      'https://api.cloudinary.com/v1_1/dyhfkvy6u/video/upload',
      formData
    ).then(async (response) => {
      if (response.data.url) url = response.data.url;
      const newSong = {
        songName,
        songLink: url,
        userId,
      };
      const song = await dispatch(postSong(newSong)).catch(async (res) => {
        const data = await res.json();
        if (data && data.errors) setErrors(data.errors);

        // Hide the form 
        setAddShowForm(false);
      });
    });
  };  

CodePudding user response:

You cant trigger useEffect with a dispatch variable change. Dispatch is a hook and dont change once invoked. You need to create a state variable useState and change its value on handleChange, when you do that, include that variable on useEffect instead of dispatch and that will trigger the useEffect content.

  • Related