Reputation: 45
I have problem and I don't know how to fix it. So i have component in which I've declared an array of objects. I want to set its state separately but I don't want to declare multiple useStates.
I have an array of objects which look like this:
const [card, setCard] = useState({
name: "",
questions: [
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
],
});
and here's component:
const NewCard = () => {
const handleNameChange = (event) => {
setCard({ name: event.target.value, ...questions });
};
return (
<div className="newcard-container">
<div className="card-container">
<h3>Podaj nazwe fiszki</h3>
<input type="text" value={card.name} />
</div>
<div className="questions-container">
{card.questions.map((q) => {
return (
<div className="question">
<h4>Podaj pytanie </h4>
<input type="text" value={q.question} />
<h4>Podaj odpowiedź</h4>
<input type="text" value={q.answer} />
</div>
);
})}
<button>Dodaj pytanie</button>
</div>
</div>
);
};
I've tried to figure out how to change the setState to get that approach but I didn't made it. Any ideas how can I get that?
Upvotes: 2
Views: 1388
Reputation: 401
Again, not sure if this is what you needed so let me know.
import React, { useState, useCallback } from 'react';
export function App() {
const [card, setCard] = useState({
name: "",
questions: [
{
id: 'question-1',
question: "Question 1",
answer: "",
},
{
id: 'question-2',
question: "Question 2",
answer: "",
},
{
id: 'question-3',
question: "Question 3",
answer: "",
},
]
});
const handleCardNameChange = useCallback((ev) => {
setCard((c) => ({ ...c, name: ev.target.value }))
}, [setCard]);
const handleAnswerChange = useCallback((cardId, value) => {
const updatedQuestions = card.questions.map((c) => {
if (c.id !== cardId) {
return c;
}
return {
...c,
answer: value,
}
});
setCard({
...card,
questions: updatedQuestions,
})
}, [card, setCard]);
return (
<div>
<input placeholder="Card Title" value={card.name} onChange={handleCardNameChange} />
{card.questions.map((c) => (
<div key={c.id}>
<p>Q: {c.question}</p>
<input placeholder="Answer" value={c.answer} onChange={(ev) => handleAnswerChange(c.id, ev.target.value)} />
</div>
))}
</div>
);
}
This handles answer change per question and card title change separately. I wrote this in a some weird editor online so it might not be perfect but it should work.
Upvotes: 2
Reputation: 1
You have a few approaches to do this.
const [ card, setCard ] = useState( {
name: "",
questions: {
1: {
statement: "",
answer: "",
},
2: {
statement: "",
answer: "",
},
//...
}
} );
// To set an especifique answer or question, you can set the state like this:
setCard( prev => ( {
...prev,
questions: {
...prev.questions,
1: {
...prev.questions[ 1 ],
answer: "New answer"
}
}
} ) );
// To add a new question, you can set the state like this:
setCard( prev => ( {
...prev,
questions: {
...prev.questions,
[ Object.keys( prev.questions ).length + 1 ]: {
statement: "",
answer: "",
}
}
} ) );
// To remove a question, you can set the state like this:
setCard( prev => {
const questions = { ...prev.questions };
delete questions[ 1 ];
return {
...prev,
questions
};
} );
But if you wanna use with array, you can do like this:
// Solution with array
const [card, setCard] = useState({
name: "",
questions: [
{
question: "",
answer: "",
},
{
question: "",
answer: "",
},
//...
],
} );
// To set an especifique answer or question, you will need the index of the question, or null to set a new question.
const setCardQuestions = ( index, question, answer ) => {
setCard( ( prev ) => {
const questions = [...prev.questions];
if ( index === null ) {
questions.push( {
question,
answer,
} );
} else {
questions[ index ] = {
question,
answer,
};
}
return {
...prev,
questions,
};
});
};
// To remove a question, you will need the index of the question.
const removeCardQuestion = ( index ) => {
setCard( ( prev ) => {
const questions = [...prev.questions];
questions.splice( index, 1 );
return {
...prev,
questions,
};
});
}
Upvotes: 0
Reputation: 159
it should be
setCard((card) => { ...card , name: event.target.value });
Upvotes: 1