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.