I’m following two React courses on the "lifting state up" portion of State management and I’m having issues with the "lifting state up" concept on React and they are rejecting my code because of this error: "Form.jsx:58 Uncaught TypeError: props.onSaveStudioData is not a function" As a result, the addition of a New Studio from the form submission isn’t being brought to the App component and just gets stuck on this error.
Not sure why, I’ve already tried the following:
- Double checking the parent and sibling components (NewStudio and
App) to see if there were any typos and there were indeed none. - Making the Form function have multiple states instead of one state
configuration, but it still renders the problem. - Changing the
parameter on the Form function component to "props", but it creates
a separate error.
Here’s the code of my Form component. It looks like the inputs were correctly upon checking. What could be causing the type error?
export default function Form( props ) {
const manilaCities = ["Bulacan", "Caloocan", "Navotas", "Pasig", "Parañaque", "Quezon City", "San Juan", "Taguig"];
const [inputtedTitle, setTitle] = useState('')
const [inputtedAddress, setAddress] = useState('')
const [inputtedCity, setCity] = useState('')
const titleChangeHandler = (event) => {
setTitle(event.target.value);
};
const addressChangeHandler = (event) => {
setAddress(event.target.value);
}
const cityChangeHandler = (event) => {
setCity(event.target.value);
};
const submitText = (event) => {
event.preventDefault();
// setTitle(event.target.value);
// setAddress(event.target.value);
// setCity(event.target.value);
const studioData = {
name: inputtedTitle,
address: inputtedAddress,
city: inputtedCity
}
props.onSaveStudioData(studioData);
setTitle('');
setAddress('');
setCity('');
}
const cityOption = manilaCities.map((city, index) => <option key={index} value={city}> {city} </option>)
return (
<div>
<form onSubmit={submitText} className={`bg-sky-500 flex flex-col p-8 m-12 text-center rounded-2xl ${props.isVisible ? "" : "hidden"} `}>
<label htmlFor="">Studio Name</label>
<input type="text" name="studio-name" value={inputtedTitle} onChange={titleChangeHandler} />
<label htmlFor="">Address </label>
<input type="text" name="Hey" value={inputtedAddress} onChange={addressChangeHandler} />
<label htmlFor=""> City </label>
<select value={inputtedCity} onChange={cityChangeHandler} >
{cityOption}
</select>
<label htmlFor=""> Studio Image </label>
<span className="m-1"><input type="file" name="Hey" id="" /></span>
<span className="inline-block"><button type="submit" className="rounded-full bg-sky-50 py-2 px-4 m-1">Add Studio</button></span>
</form>
</div>
);
}
As suggested, here’s the code of other two components:
NewStudio (sibling):
import Form from '../Form';
export default function NewStudio(props) {
const saveStudioDataHandler = (enteredStudioData) => {
const studioData = {
...enteredStudioData,
id: Math.random().toString()
};
props.onAddStudio(studioData);
}
return (
<div>
<Form onSaveStudioData = {saveStudioDataHandler} />
</div>
)
}
App (parent)
import Form from './components/Form';
import StudioList from './components/Studios/StudioList'
import { useState } from 'react';
import NewStudio from './components/Studios/NewStudio';
export default function App() {
const [isFormVisible, setIsFormVisible] = useState(false);
const toggleFormVisibility = () => {
setIsFormVisible(!isFormVisible);
}
const addStudioHandler = (studio) => {
console.log('In App.js')
console.log(studio);
}
return (
<div>
<Nav toggleForm={toggleFormVisibility}/>
<NewStudio onAddStudio={addStudioHandler}/>
<Hero/>
<Form isVisible={isFormVisible} />
<StudioList/>
</div>
)
}
Edit: Removed unnecessary comments on each of the change handler events.
2
Answers
Thank you to both @A1asd and @Nick Parsons. Both solutions were correct,
what helped was changing the Form component on App into
It looks to me that you do not pass the right variable as a prop
Try following code, where you are using your
<Form>
Componentwhere onSaveStudioData should be a function, because you are using it like that in your component.
For better help you should also post more context, in this case the parent component would be very helpful
Edit after Question was updated:
Your parent uses the
<Form>
component but never passes a prop called onSaveStudioData. But I also see another problem. I think you want to hide your form in the parent with the isVisible prop, but this doesnt do anything other than just passing a boolean down to the form. If you want to hide your Form component you should consider conditional rendering in your App.js, like