I’m trying to update a state from an input, which works fine when the field is is in the same component, but doesn’t work when I pass it into a child component, seemingly no matter what I pass to it!
const Create = () => {
const [question, setQuestion] = useState('');
const [components, setComponents] = useState([""]);
const handleQInputChange = event => {
setQuestion(event.target.value)
}
function addComponent() {
setComponents([...components, "Question"])
}
return (
<Button onClick={addComponent} text="Next question"/>
<ol>
{components.map((item, i) => (
<li>
<CreateQuestion question={question} onChange=
{handleQInputChange}/>
</li>
))}
</ol>
)}
and then CreateQuestion component looks like:
const CreateQuestion = (props) => {
function handleQInputChange( event ) {
props.onChange(event.target.value)
}
return (
<div className="Component">
<label>Question</label>
<input
name="question"
id="question"
value={props.value}
onChange={props.handleQInputChange}
type="text"
placeholder="Question"
/>
<br />
I've followed at least 10 guides on how to pass the data back and forth, so it may have become a little convoluted. If I put the Question input directly into the parent component the state updates, so I suspect it's just me not passing props correctly but completely stuck!
Thank you
CodePudding user response:
You are doing a lot of wrong things:
- Using wrong props.
- Passing
event.target.value
which is a string, toprops.onChange
which is a function that accepts a typeEvent
. - Declaring the controlled input state on the parent, while you need the state local to the input, since you have multiple inputs and I don't think you want to share the same state among them.
function App() {
const [questions, setQuestions] = useState([]);
const [components, setComponents] = useState(['']);
function addComponent() {
setComponents([...components, 'Question']);
}
function addQuestion(question) {
setQuestions((qs) => [...qs, question]);
}
return (
<>
<Button onClick={addComponent} text="Next question" />
<ol>
{components.map((item, i) => (
<li>
<CreateQuestion idx={i} addQuestion={addQuestion} />
</li>
))}
</ol>
<ul>
<h5>Submitted Questions:</h5>
{questions.map((question, i) => (
<li>
<span style={{ marginRight: '10px' }}>
Question n.{question.id}
</span>
<span>{question.body}</span>
</li>
))}
</ul>
</>
);
}
const CreateQuestion = ({ addQuestion, idx }) => {
const [question, setQuestion] = useState('');
const handleChange = (event) => {
setQuestion(event.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
addQuestion({ id: idx 1, body: question });
};
return (
<div className="Component">
<form onSubmit={handleSubmit}>
<label></label>
<input
name="question"
id="question"
value={question}
onChange={handleChange}
type="text"
placeholder="Question"
/>
<button>ADD QUESTION</button>
</form>
</div>
);
};
I refactored your code in this demo https://stackblitz.com/edit/react-h7m1cu check if it helps you.
I fixed the main issues, moved the input state down to the CreateQuestion
Component, added a function and a state to the Parent Component that holds all the questions added when you submit the input, this way you can handle data in your Parent, if for example you want to send it to your server.
CodePudding user response:
Please change your CreateQuestion component like below
const CreateQuestion = (props) => {
return (
<div className="Component">
<label>Question</label>
<input
name="question"
id="question"
value={props.value}
onChange={props.onChange}
type="text"
placeholder="Question"
/>
</div>
);
}
The problem is
You use an attribute like
onChange={props.handleQInputChange}
But you do not have handleQInputChange when you call your component as an attribute
<CreateQuestion question={question} onChange=
{handleQInputChange}/>