最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - React - How to loop and update values in object model? - Stack Overflow

programmeradmin0浏览0评论

I have an object model pattern as below

   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'
             }
         }
    }

My goal is to:

  1. Loop through the data and render
  2. Map value changes in the HTML to the corresponding keys in the this.state.data object

I haven't used an Array, as it has to look like above object pattern when posting it.

At the moment here is how I am trying to do this:

//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}/>
)

Then to update the corresponding values in the same state model:

// 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);
};

Please could anyone advise me on this approach, many thanks :)

I have an object model pattern as below

   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'
             }
         }
    }

My goal is to:

  1. Loop through the data and render
  2. Map value changes in the HTML to the corresponding keys in the this.state.data object

I haven't used an Array, as it has to look like above object pattern when posting it.

At the moment here is how I am trying to do this:

//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}/>
)

Then to update the corresponding values in the same state model:

// 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);
};

Please could anyone advise me on this approach, many thanks :)

Share Improve this question asked Nov 13, 2020 at 13:05 Wisdom1Wisdom1 1291 silver badge8 bronze badges 2
  • What issue you are facing actually? – Aadil Mehraj Commented Nov 13, 2020 at 13:10
  • How exactly you are expecting it, share sample if possible? – Priyanka Panjabi Commented Nov 13, 2020 at 13:24
Add a ment  | 

3 Answers 3

Reset to default 3

First you need to get the rendering right, which means looping over all the keys (car makers) and then all the property/value pairs. You can use destructuring arrays to make this easier

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

Heres rendering:

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>
      );
    });
  }

You'll note I changed your handleChange method to pass the car maker and the property being edited - this can be passed to setData :

// 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);
  };

Live working example: https://codesandbox.io/s/react-playground-forked-dw9sg

You are not passing key and event object from the input callback in the first place, your code should be like,

The display logic looks wrong to me,

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}/>
)

and handleChange callback should look like, don't curry them.

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

And I would suggest using a utility like castArray from lodash, https://lodash./docs/4.17.15#castArray to convert the object to an array so that you can easily work with it.

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"))
body { font-family: monospace; }
span { display: block; font-weight: bold; }
input { width: 50px; }
<script src="https://cdnjs.cloudflare./ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>

发布评论

评论列表(0)

  1. 暂无评论