Reputation: 327
Basically, I want to pass the "filename" state from child component to the parent component. So that, I can use the "filename" state in the onSubmit function at parent. How can I achieve that? Currently filename at parent is not defined. Thanks a lot for your help.
Parent:
const AddLocation = ({ addLocation }) => {
const initialFormState = { title: '', thumbnail: '' };
const [location, setLocation] = useState(initialFormState);
const onChange = (e) => {
setLocation({ ...location, [e.target.name]: e.target.value });
};
const onSubmit = () => {
addLocation({
...location,
thumbnail: filename // I want to use filename state from child here.
});
};
return (
<form onSubmit={onSubmit}>
<TextInput
id="add-loc-title"
name="title"
value={location.title}
onChange={onChange}
/>
<FileUpload />
<Button type="submit">Submit</Button>
</form>
);
};
Child:
const FileUpload = () => {
const [file, setFile] = useState('');
const [filename, setFilename] = useState('Choose File');
const onChange = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
};
const onSubmit = async () => {
const formData = new FormData();
formData.append('file', file);
await axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
};
return (
<form onSubmit={onSubmit}>
<TextInput
id="add-cat-thumb"
name="thumbnail"
type="file"
onChange={onChange}
</form>
</>
);
};
Upvotes: 1
Views: 91
Reputation: 3043
You should handle a state at Parent and pass the setState to the Child. Then call it on event.
Parent:
const [file, setFile] = useState(''); // create a state as the parent
const onSubmit = () => {
addItem({
...item,
file: filename
});
};
return <FileUpload parentSetFile={setFile}/>
Then use parentSetFile
in Child:
const onChange = (e) => {
props.parentSetFile(e.target.files[0]) // For Example
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
};
Edit after full code posted:
So I assume you want the file will be updated in the parent after the submit succeeded, then you should do something like that:
Parent:
const AddLocation = ({ addLocation }) => {
const initialFormState = { title: '', thumbnail: '' };
const [location, setLocation] = useState(initialFormState);
const [submittedFileName, setSubmittedFileName] = useState(null); // New state here to save the submitted file from child.
const onChange = (e) => {
setLocation({ ...location, [e.target.name]: e.target.value });
};
const onSubmit = () => {
addLocation({
...location,
thumbnail: submittedFileName // Use the submitted file name - a state handled in this component (Parent)
});
};
return (
<form onSubmit={onSubmit}>
<TextInput
id="add-loc-title"
name="title"
value={location.title}
onChange={onChange}
/>
<FileUpload updateFileNameToParent={setSubmittedFileName} /> // Pass teh function that sets submittedFileName to the child so he could use it anyware he wants (probably after submit).
<Button type="submit">Submit</Button>
</form>
);
};
Child:
const FileUpload = (props) => { // Since this component now gets props, we should pass it here
const [file, setFile] = useState('');
const [filename, setFilename] = useState('Choose File');
const onChange = (e) => {
setFile(e.target.files[0]);
setFilename(e.target.files[0].name);
};
const onSubmit = async () => {
const formData = new FormData();
formData.append('file', file);
await axios.post('/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
props.updateFileNameToParent(filename) // Call the function that sets submitedFileName for parent with the filename in the state of this component (Child)
};
return (
<form onSubmit={onSubmit}>
<TextInput
id="add-cat-thumb"
name="thumbnail"
type="file"
onChange={onChange}
</form>
</>
);
};
Upvotes: 1
Reputation: 2619
The basic idea is like this: Let's suppose you have a react component called < Parent > with state variable fileName. Let's suppose you need to run another react component called < TheChild > from the Parent's render function. Then, to use the Parent's medthods, functions, state vars, etc. at TheChild you could pass the reference of the parent to the child as with:
return(
...
<TheChild calledMe={this} />
...
)
this will allow you to use this.props.calledMe within TheChild's code to update the state of the Parent component as with:
this.props.calledMe.setState({fileName: .......}, () => {maybe do something else with fileName state variable})
Upvotes: 1