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

javascript - React: How to set state of object property? - Stack Overflow

programmeradmin1浏览0评论

I am a beginner with React and I have been using the NPM package react- tabs in order to display tabs on my site.

I have been trying to allow the user to update descriptions of their profiles using a checkbox to open an input type=text tag allowing the user to put in their own details for their profile.

However, I am struggling to set the state of the description for the tab using the handleDesc function. I am not sure how I can update the state of the descriptions for each tab. I keep getting the error "A ponent is changing a controlled input of type checkbox to be uncontrolled."

Can anyone help me?

class EditSite extends React.Component {
constructor(props) {
    super(props);
    this.state = {About: true,
        "Opening Hours": true,
        Contact: true,
        Menu: false,
        Offers: false,
        "External Links": true,
        tabOptions: {
            About: {desc:'1'},
            "Opening Hours": {desc: '2'},
            Contact: {desc:'3'},
            Menu: {desc:'4'},
            Offers: {desc:'5'},
            "External Links": {desc:'6'},
            }
        }

Below is the function (handleDesc) I am struggling with to set the state of the descriptions.

handleDesc = (event) => {
    let tabOptions = {...this.state.tabOptions[event.target.name]};
    tabOptions = event.target.value;
    console.log(tabOptions);
    this.setState({tabOptions: [event.target.name]});
}   

 render() {
    const links = [];
    const tabs = [];
    const tabPanels = [];

The second input tag is where I would like the user to be able to add their own details to the specific tab.

Object.keys(this.state.tabOptions).forEach(name => {
  links.push(
      <div>
      <label key={name}>{name}</label>
      <input
        type="checkbox"
        checked={this.state[name]}
        name={name}
        onChange={this.handleCheckClicked}
      />
      { this.state[name] === true ? (
      <input
      name={name}
      type='text'
      onChange={this.handleDesc}
      />
      ) : null }
      </div>
  );

  if (!this.state[name]) return;

  const { desc } = this.state.tabOptions[name];

  tabs.push(
    <Tab>
      <h3>{name}</h3>
    </Tab>
  );

  tabPanels.push(
    <TabPanel> 
        {desc}
    </TabPanel>
  );
});

I am a beginner with React and I have been using the NPM package react- tabs in order to display tabs on my site.

I have been trying to allow the user to update descriptions of their profiles using a checkbox to open an input type=text tag allowing the user to put in their own details for their profile.

However, I am struggling to set the state of the description for the tab using the handleDesc function. I am not sure how I can update the state of the descriptions for each tab. I keep getting the error "A ponent is changing a controlled input of type checkbox to be uncontrolled."

Can anyone help me?

class EditSite extends React.Component {
constructor(props) {
    super(props);
    this.state = {About: true,
        "Opening Hours": true,
        Contact: true,
        Menu: false,
        Offers: false,
        "External Links": true,
        tabOptions: {
            About: {desc:'1'},
            "Opening Hours": {desc: '2'},
            Contact: {desc:'3'},
            Menu: {desc:'4'},
            Offers: {desc:'5'},
            "External Links": {desc:'6'},
            }
        }

Below is the function (handleDesc) I am struggling with to set the state of the descriptions.

handleDesc = (event) => {
    let tabOptions = {...this.state.tabOptions[event.target.name]};
    tabOptions = event.target.value;
    console.log(tabOptions);
    this.setState({tabOptions: [event.target.name]});
}   

 render() {
    const links = [];
    const tabs = [];
    const tabPanels = [];

The second input tag is where I would like the user to be able to add their own details to the specific tab.

Object.keys(this.state.tabOptions).forEach(name => {
  links.push(
      <div>
      <label key={name}>{name}</label>
      <input
        type="checkbox"
        checked={this.state[name]}
        name={name}
        onChange={this.handleCheckClicked}
      />
      { this.state[name] === true ? (
      <input
      name={name}
      type='text'
      onChange={this.handleDesc}
      />
      ) : null }
      </div>
  );

  if (!this.state[name]) return;

  const { desc } = this.state.tabOptions[name];

  tabs.push(
    <Tab>
      <h3>{name}</h3>
    </Tab>
  );

  tabPanels.push(
    <TabPanel> 
        {desc}
    </TabPanel>
  );
});
Share Improve this question asked Oct 8, 2018 at 22:18 John MuttonJohn Mutton 531 gold badge1 silver badge8 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 1

SetState wants a new object. So settings just a property of a nested object isn’t possible in that way. What you could do is copying the tabOptions and changing the properties you want before you pass it to setState.

example

handleDesc = (event) => {

const newTabOptions = {
  ...this.state.tabOptions,
  [event.target.name]: {desc: event.target.value}

this.setState({tabOptions: newTabOptions});
}   

A quick way to resolve this would be to revise that code that binds the <input /> element's onChange handler to the following:

links.push(
      <div>
      <label key={name}>{name}</label>
      <input
        type="checkbox"
        checked={this.state[name]}
        name={name}
        onChange={ (event) => this.handleCheckClicked(event) /* <-- update this also */ }
      />
      { this.state[name] === true ? (
      <input
      name={name}
      type='text'
      onChange={ (event) => this.handleDesc(event) /* [ UPDATE HERE ] */ } 
      />
      ) : null }
      </div>
  );

By declaring an arrow function inline like this:

onChange={ (event) => this.handleDesc(event) }

it will set the context of the handleDesc function to be the <EditSite /> ponent (currently, the context will be the global window object). This means that when you access this.state, or call a method like this.setState() inside of the handleDesc, it will work as expected.

For more information on this subtle characteristic of "arrow functions" see this article.

Update

Also, consider updating your handleDesc method like so to correctly mutate your state:

handleDesc = (event) => {
    let tabOptions = {...this.state.tabOptions[event.target.name]};
    tabOptions = event.target.value;
    console.log(tabOptions);
    this.setState({tabOptions}); // <--- Update this line
}  

Update 2

On further investigation (into react's source code), it would see the problem is that your <input /> element does not have a checked attribute when this.state[name] === true is satisfied. If you apply a dummy attribute/value pair of checked={ true } on the input rendered in the this.state[name] === true case, this warning message should stop showing:

links.push(
  <div>
  <label key={name}>{name}</label>
  <input
    type="checkbox"
    checked={this.state[name]}
    name={name}
    onChange={this.handleCheckClicked}
  />
  { this.state[name] === true ? (
  <input
  name={name}
  type='text'
  checked={ true } /* <-- Update this line, don't include this ment in code */
  onChange={this.handleDesc}
  />
  ) : null }
  </div>
 );
发布评论

评论列表(0)

  1. 暂无评论