4
votes

React - Comment boucler et mettre à jour les valeurs dans le modèle objet?

J'ai un modèle de modèle d'objet comme ci-dessous

// To update the state model with changed values
setData = (key, val) => {
    this.setState(state => ({
        data: {
            ...state.data,
            obj: { [key]: val },
            //Don't know how to map to state properly!
        }
    }));
};

// Handle input change
handleChange = key => e => {
    this.setData(key, e.target.value);
};

Mon objectif est de:

  1. Parcourez les données et effectuez le rendu
  2. Mappez les changements de valeur dans le HTML aux clés correspondantes dans l'objet this.state.data

Je n'ai pas utilisé de tableau, car il doit ressembler au modèle d'objet ci-dessus lors de sa publication.

Pour le moment, voici comment j'essaye de faire ceci:

//To render
Object.entries(this.state.data).map((x,index) =>
    <p>x.key</p> //Trying to reach 'audi' with x.key

    // Render each KPV in object
    {x.key}: <input key={index} onChange={this.handleChange} value={x.value}/>
)

Ensuite, pour mettre à jour les valeurs correspondantes dans le même modèle d'état:

   this.state = {
        data: {
            audi: {
                 engine: '2.5',
                 gearbox: 'auto',
                 fuel: 'petrol'
             },
             bmw: {
                 engine: '3.0',
                 gearbox: 'auto',
                 fuel: 'petrol'
             },
             merc: {
                 engine: '6.3',
                 gearbox: 'manual',
                 fuel: 'petrol'
             }
         }
    }

S'il vous plaît, quelqu'un pourrait-il me conseiller sur cette approche, merci beaucoup :)


2 commentaires

À quel problème êtes-vous confronté en fait?


Comment l'attendez-vous exactement, partagez un échantillon si possible?


3 Réponses :


1
votes

Vous ne passez pas la clé et l'objet d'événement à partir du rappel d'entrée en premier lieu, votre code devrait être comme,

La logique d'affichage me semble fausse,

handleChange = (key, e) => {
    this.setData(key, e.target.value);
};

et le rappel handleChange devrait ressembler à, ne les curry pas.

Object.entries(this.state.data).map((x, index) =>
    /* 
     here x is an array and it looks like 
     ["audi", {engine: '2.5', gearbox: 'auto', fuel: 'petrol}
    */
     // You need to access the data in the second index
     // if you want to print each value of the object
    <p>x[1].engine</p>
    <p>x[1].gearbox</p>
    <p>x[1].fuel</p> 

    // Render each KPV in object
    {x[0]}: <input key={index} onChange={(e) => this.handleChange(x[0], e)} value={x[1].engine}/>
)

Et je suggérerais d'utiliser un utilitaire tel que castArray de lodash, https://lodash.com/docs/4.17.15#castArray pour convertir l'objet en tableau afin que vous puissiez facilement travailler avec lui.


0 commentaires

2
votes

Vous devez d'abord obtenir le bon rendu, ce qui signifie boucler toutes les clés (constructeurs automobiles), puis toutes les paires propriété / valeur. Vous pouvez utiliser des tableaux de déstructuration pour rendre cela plus facile

// To update the state model with changed values
  setData = (maker, key, val) => {
    this.setState((state) => ({
      data: {
        ...state.data,
        [maker]: {
          ...state.data[maker],
          [key]: val
        }
        //Don't know how to map to state properly! Now you do!
      }
    }));
  };

  // Handle input change
  handleChange = (maker, key) => (e) => {
    this.setData(maker, key, e.target.value);
  };

Rendu Heres:

render() {
    return Object.entries(this.state.data).map(([maker, props]) => {
      return (
        <div>
          <h2>{maker}</h2>
          {Object.entries(props).map(([key, value], index) => {
            return (
              <div>
                {key}:{" "}
                <input
                  key={index}
                  onChange={this.handleChange(maker, key)}
                  defaultValue={value}
                />
              </div>
            );
          })}
        </div>
      );
    });
  }

Vous noterez que j'ai changé votre méthode handleChange pour transmettre le constructeur automobile et la propriété en cours de modification - cela peut être passé à setData :

Object.entries(someObject).map( ([key,value]) => .... )

Exemple de travail en direct: https://codesandbox.io/s/react-playground-forked-dw9sg


1 commentaires

Merci @Jamiec cela m'a aidé beaucoup



1
votes

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
body { font-family: monospace; }
span { display: block; font-weight: bold; }
input { width: 50px; }
class App extends React.Component {
  constructor(props) {
    super(props)
    this.state = { 
      data: {
        audi: { model: "A7", transmission: "AT" },
        merc: { model: "GLA", transmission: "MT" },
        bmw: { model: "M3", transmission: "AT" },
      },
    }
  }
  update(make, detail, value) {
    let data = this.state.data
    data[make][detail] = value
    console.log(`Updating ${make} ${detail} with ${value}`)
    this.setState({ data: data })
  }
  handleChange(make, detail) {
    return e => { this.update(make, detail, e.target.value) }
  }
  renderDetails(details) {
    return details.map(d => (<div><span>{d.key}:</span> <input value={d.model} onChange={this.handleChange(d.key, "model")} /> <input value={d.transmission} onChange={this.handleChange(d.key, "transmission")} /></div>))
  }
  render() {
    const details = Object.entries(this.state.data).map(d => ({ key: d[0], ...d[1] }))
    return <div>{this.renderDetails(details)}</div>
  }
}

ReactDOM.render((<App />), document.getElementById("app"))


0 commentaires