J'essaie d'envoyer la liste des ID de bouton radio sélectionnés à partir de plusieurs groupes de boutons radio en cliquant sur le bouton Envoyer,
Mon problème: Je suis en train de sélectionner le bouton radio du backend, je devrais alors pouvoir le changer et le renvoyer au backend. mais lorsque j'essaie de changer le bouton radio, cela ne fonctionne pas.
Ce que je ne comprenais pas: Comment gérer la fonction on change, normalement lors d’un changement, nous pouvons changer l’état, mais pour changer l’état à la charge, nous devons saisir les boutons radio de valeurs. Finalement, j'ai été frappé ici, ne comprenant pas comment avancer.
Voici l'extrait de filaire et de code:
function CardsList(props) {
const cards = props.cards;
return (
<div>
{cards.map((card, idx) => (
<div>
{card.cardName}
{
card.options.map((lo,idx) => (
<li key={idx}>
<input
className="default"
type="radio"
name={card.cardName}
checked={lo.selected}
/>))
}
<div>
))}
</div>
);
}
//array of cards coming from the backend
const cards = [
{cardName:'card1',options:[{radioName:'card1-radio1',selected:'true'},
{radioName:'card1-radio2',selected:'false'}]},
{cardName:'card2',options:[{radioName:'card2-radio1',selected:'true'},
{radioName:'card2-radio2',selected:'false'}]}
];
ReactDOM.render(
<CardsList cards={cards} />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Vous pouvez utiliser un objet en tant que table de recherche contenant les noms de groupe en tant que clés.
À chaque changement, vous devrez trouver le groupe approprié avec l’option appropriée et définir le nouvel état en conséquence.
Important! - Une chose à noter ici est que j’ai modifié le type de la propriété selected
de String
à Boolean
. cela me permettra de gérer les conditions comme ceci:
<input checked={option.selected} />
Si vous ne pouvez pas le changer en Boolean
, vous devrez gérer la condition de la manière suivante:
<input checked={option.selected === 'true'} />
Voici un exemple en cours d'exécution:
//array of cards coming from the backend
const data = [
{
cardName: 'card1', options: [{ radioName: 'card1-radio1', selected: true },
{ radioName: 'card1-radio2', selected: false }]
},
{
cardName: 'card2', options: [{ radioName: 'card2-radio1', selected: true },
{ radioName: 'card2-radio2', selected: false }]
}
];
class CardsList extends React.Component {
constructor(props) {
super(props);
this.state = {
cards: []
};
}
componentDidMount() {
setTimeout(() => {
// mimic an async server call
this.setState({ cards: data });
}, 1000);
}
onInputChange = ({ target }) => {
const { cards } = this.state;
const nexState = cards.map(card => {
if (card.cardName !== target.name) return card;
return {
...card,
options: card.options.map(opt => {
const checked = opt.radioName === target.value;
return {
...opt,
selected: checked
}
})
}
});
this.setState({ cards: nexState })
}
onSubmit = () => { console.log(this.state.cards) };
render() {
const { cards } = this.state;
return (
<div>
{
cards.length < 1 ? "Loading..." :
<div>
{cards.map((card, idx) => (
<ul>
{card.cardName}
{
card.options.map((lo, idx) => {
return <input
key={idx}
type="radio"
name={card.cardName}
value={lo.radioName}
checked={!!lo.selected}
onChange={this.onInputChange}
/>
})
}
</ul>
))
}
< button onClick={this.onSubmit}>Print Cards</button>
</div>
}
</div>
);
}
}
ReactDOM.render(<CardsList />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
La raison pour laquelle vous ne pouvez pas les modifier est due à leur état coché actuel que vous définissez ici:
<input
className="default"
type="radio"
name={card.cardName}
checked={lo.selected}
/>
Une approche que j'ai utilisée pour ce scénario exact consiste à stocker l'état du composant (à partir du serveur) dans l'état de mon composant (this.state
), à transmettre l'état à l'élément: checked={this.state.isChecked}
et à mettre à jour l'état de l'élément onClick
.
Exemple:
class CardsList extends Component {
constructor(props){
super(props);
this.state = {isChecked: false};
this.inputOnClick = this.inputOnClick.bind(this);
}
//fetch data from server
fetchData(){
fetch('/api')
.then(res => res.json())
//this will be our initial state
.then(res => this.setState(res))
}
componentDidMount(){
this.fetchData();
}
//change radio button state on click
inputOnClick(e){
e.preventDefault();
//invert state value
this.setState((prevState, props) => {isChecked: !prevState.isChecked});
}
render(){
return (
<input
type="radio"
checked={this.state.isChecked}
onClick={this.inputOnClick}
/>
)
}
}
cette réponse peut fonctionner avec un seul groupe de boutons radio, mais je rencontre un problème de avec plusieurs boutons radio avec dans plusieurs groupes de boutons radio . Si vous voyez le tableau de cartes, comment sait-il quelle radio? groupe de boutons auquel il appartient.
Nous pouvons modifier l'état en fonction du nom du bouton radio.
Sauvegardons toutes vos cartes dans l'état de votre composant. Je sais que les cartes sont extraites du serveur et seront sauvegardées avec setState
mais je l’écris comme ceci à des fins visuelles.
this.state = {cards: [
{ cardName:'card1',
options:[
{radioName:'card1-radio1',selected:true},
{radioName:'card1-radio2',selected:false}
]
},
{ cardName:'card2',
options:[
{radioName:'card2-radio1',selected:true},
{radioName:'card2-radio2',selected:false}
]
}
]}
Maintenant, lorsque nous cliquons sur un bouton radio, nous allons utiliser le nom de ce bouton pour mettre à jour l'état dans lequel il doit être mis à jour. Étant donné que l'état de réaction doit être immuable, nous allons créer une copie complète de l'état, le modifier, puis définir l'état avec.
inputOnClick(e){
e.preventDefault();
var thisRadioBtn = e.target.name;
//make a deep copy of the state
const stateCopy = JSON.parse(JSON.stringify(this.state.cards));
//go through state copy and update it
stateCopy.forEach(card => {
card.options.forEach(option => {
if(option.radioName === thisRadioBtn){
//invert value
//make sure the values are booleans
option.selected = !option.selected;
}
});
});
//update the components state
this.setState({cards: stateCopy});
}