不确定为什么国家正在改变

时间:2017-03-31 16:09:04

标签: javascript reactjs ecmascript-6

我在子组件中有一个用于调试目的的按钮,用于在其父组件中打印当前状态。当它打印时,这就是我想要的状态。当我点击同一子组件中的另一个按钮时,通过删除一些属性,状态在父级中发生变化。

请注意现在缺少IdSEO_CSEO_Survey_Questions__r属性。

子组件

import React, { Component } from 'react';
import { Link } from 'react-router';

class Index extends Component {

  constructor(props){
    super(props)

    this.state = {
      selected: 'created'
    }

    this.updatePreview = this.updatePreview.bind(this);
    this.renderEditArea = this.renderEditArea.bind(this);
  }

  isActive(value) {
      return 'slds-tabs--default__item '+((value===this.state.selected) ?'slds-active':'');
  }

  updatePreview(e){
    const updatedPreview = {
      ...this.props.selectedPreview,
      [e.target.name]: e.target.value
    };
    this.props.update(updatedPreview)
  }

  // determines which type of edit area should display
  // survey settings or question
  renderEditArea() {
    let selected = this.props.selectedPreview;
    let hasNameKey = "Name" in selected;
    if(hasNameKey){
      return (
        <div>
          <input
            onChange={(e) => this.updatePreview(e)}
            name="Name"
            type="text"
            className="slds-input"
            value={selected.Name ? selected.Name : ''}
          />
          <input
            onChange={(e) => this.updatePreview(e)}
            name="SEO__Welcome_Text__c"
            type="text"
            className="slds-input"
            value={selected.SEO__Welcome_Text__c ? selected.SEO__Welcome_Text__c : ''}
          />
        </div>
      )
    }else {
      return (
        <input
          onChange={(e) => this.updatePreview(e)}
          name="SEO__Question__c"
          type="text"
          className="slds-input"
          value={selected.SEO__Question__c ? selected.SEO__Question__c : ''}
        />
      )
    }
  }

  render() {
    return (
      <div className="slds-size--1-of-1 slds-medium-size--4-of-5 slds-large-size--4-of-5">
        <div className="slds-tabs--default">
          <h2 className="slds-text-heading--small slds-p-top--x-small" style={{position: "absolute"}}>
            <button onClick={this.props.addQuestion} className="slds-button slds-button--icon slds-p-left--xx-small" title="add sur">
              <svg className="slds-button__icon slds-button__icon--medium" aria-hidden="true">
                <use xlinkHref={addIcon}></use>
              </svg>
              <span className="slds-assistive-text">Add Question</span>
            </button>
          </h2>
          <ul className="slds-tabs--default__nav" style={{justifyContent: "flex-end"}}>
            <Link to="/"className="slds-button slds-button--neutral">Back</Link>
            <button onClick={this.props.save} className="slds-button slds-button--brand">Save</button>
            <button onClick={this.props.currentState} className="slds-button slds-button--brand">Current State</button>            
          </ul>
        </div>
        <div className="slds-grid slds-wrap slds-grid--pull-padded">
          {this.renderEditArea()}
        </div>
      </div>
    );
  }
}

export default Index;

import React, { Component } from 'react';
import { getQuestions, addQuestion, deleteQuestion, newSurveyQuestions, updateSurveyQuestions, EMPTY_SURVEY } from './helpers';

import SideBar from './survey/SideBar';
import MainArea from './survey/Index';

class Survey extends Component {

  constructor(props) {
    super(props)

    this.state = {
      survey: [],
      selectedPreview: []
    }

    this.componentWillMount = this.componentWillMount.bind(this);
    this.save = this.save.bind(this);
    this.setSelectedPreview = this.setSelectedPreview.bind(this);
    this.currentState = this.currentState.bind(this);
  }

  // if the url is `/survey/new`, create an empty survey
  // to save for later.
  // else if there is an id in the url, load the survey and questions
  componentWillMount(){
    if(this.props.pathname === "/survey/new") {
      this.setState({
        survey: EMPTY_SURVEY,
        selectedPreview: EMPTY_SURVEY[0]
      })
    } else if (this.props.params.surveyId){
      getQuestions(this.props.params.surveyId).then(survey => {
        // 'survey' contains all the questions
        this.setState({
          survey,
          selectedPreview: survey[0]
        });
      });
    }
  }

  currentState() {
    console.log('clicking Current State');
    console.log(this.state.survey[0]);
  }

  // saves a new survey with associated newly created questions
  // or saves an existing survey with associated questions
  save() {
    console.log('clicking Save');
    console.log(this.state.survey[0]);
    // if the url is set to survey/new
    // save new survey with associated newly created questions
    if(this.props.pathname === "/survey/new") {
      newSurveyQuestions(this.state.survey).then( id => {
        this.context.router.transitionTo(`/survey/id/${id}`);
      })

    // else update survey and questions
    } else {
      updateSurveyQuestions(this.state.survey);
    }
  }

  // sets selectedPreview for the entire component and
  // its children
  setSelectedPreview(selectedPreview) {
    this.setState({selectedPreview});
  }

  render() {
    return (
      <div className="slds-grid slds-wrap slds-grid--pull-padded">
        <SideBar
          survey={this.state.survey}
          setSelectedPreview={this.setSelectedPreview}
          deleteQuestion={this.deleteQuestion}

        />
        <MainArea
          addQuestion={this.addQuestion}
          selectedPreview={this.state.selectedPreview}
          update={this.update}
          save={this.save}
          currentState={this.currentState}
        />
      </div>
    );
  }
}

Survey.contextTypes = {
  router: React.PropTypes.object
}

export default Survey;

帮助功能

export function updateSurveyQuestions(survey) {
  // create proper url for update request
  const requestURL = `${URL + survey[0].attributes.url}`;

  // save questions for later update requests
  const questions = survey[0].SEO__CSEO_Survey_Questions__r.records;

  let s = [...survey];

  // remove properties for proper body format
  delete s[0].Id;
  delete s[0].SEO__CSEO_Survey_Questions__r;
  delete s[0].attributes;

  axios.patch(requestURL, s[0], API_TOKEN);

  questions.forEach( question => {
    // save request url for later
    let requestURL = `${URL + question.attributes.url }`;

    // remove properites for proper body format
    delete question.attributes;
    delete question.Id;

    axios.patch(requestURL, question, API_TOKEN);
  })
}

当我删除save()中的所有代码({1}}除外)时,它会按预期打印。

1 个答案:

答案 0 :(得分:1)

tl; dr:您的代码运行正常。您所看到的是对象和控制台如何工作的结果。做

console.log(this.state.survey[0].Id);

而不是看到该属性确实存在。

另见Is Chrome's JavaScript console lazy about evaluating arrays?

  

当我删除save()中的所有代码时,除了console.log之外,它会按预期打印。

这似乎表明该代码正在改变对象。例如。 updateSurveyQuestionsnewSurveyQuestions可能会移除这些属性。

您必须记住,您在控制台中看到的输出是在您展开属性时计算的console.log叫做。实际上,i旁边的小Object图标会告诉您。当你将鼠标悬停在它上面时说:

  

以下评估价值

以下是您遇到的简化示例:展开对象并注意它是空的,即使我们在调用console.dir后打开了(打开浏览器的控制台):< / p>

var obj = {foo: 42};
console.dir(obj);
delete obj.foo;

理想情况下,updateSurveyQuestionsnewSurveyQuestions不会直接改变对象,而是克隆它,对克隆进行必要的更改,然后更新组件状态(如果需要)。例如。克隆对象的简单方法是通过Object.assign

var copy = Object.assign({}, this.state.survey[0]);