当React JS中父状态发生变化时,如何在子进程中更改this.props?

时间:2016-12-14 08:03:29

标签: javascript reactjs

这里是React JS的新手。我有一个设置,其中我的App父组件具有 initialFormInput 状态,持有配方对象。函数从父组件传递到名为 EditRecipeButton 的子组件,该子组件可以将此状态更改为从编辑按钮调用的特定配方。

父级中的此状态通过via this.props 映射到子AddRecipe组件中的状态,我的理由是,只要父组件状态在AddRecipe中更改此状态也会发生变化。但这并没有发生,我在这里做错了什么?

这是我的代码:

var App = React.createClass({


  getInitialState(){

    return{

      showModal:false,


      recipeKeys: [ ],

      recipes: [ ],

      initialFormInput: {name: "", ingredients: []}

    }


  },


  open: function(){


    this.setState({showModal:true});

  },

    close: function(){

    this.setState({showModal:false});

  },

  editRecipe: function(recipe){

    console.log(recipe);

    this.setState({initialFormInput: recipe}, function(){

      this.open();  


    });


  },

  render: function(){

    return( 

      <div className="container">
        <h1>Recipe Box</h1>
        <RecipeList recipes = {this.state.recipes} deleteRecipe = {this.deleteRecipe} editRecipe={this.editRecipe} />
        <AddRecipeButton openModal = {this.open}/>
        <AddRecipe closeModal = {this.close} showModal={this.state.showModal} addRecipeKey = {this.addRecipeKey} initialFormInput = {this.state.initialFormInput}/>
      </div>

    )  

  }


var RecipeList = function (props) {

    return (
        <ul className="list-group">
            {

          props.recipes.map( (item,index) => <RecipeItem recipe={item} deleteRecipe = {props.deleteRecipe} editRecipe={props.editRecipe}/> )

            }
        </ul>  
    );
};

var RecipeItem = React.createClass({

getInitialState: function(){

    return {displayIngredients: false}

},  

toggleRecipe: function() {

  this.setState({displayIngredients: !this.state.displayIngredients})

},

render: function() {

    return(

      <li className="list-group-item" >
      <h4 onClick={this.toggleRecipe}>{this.props.recipe.name}</h4>
      <div style={{display: this.state.displayIngredients ? 'block' : 'none'}}>
      <h5 className="text-center">Ingredients</h5>
      <hr/> 
       <ul className="list-group" >
        {this.props.recipe.ingredients.map((item) => <IngredientItem ingredient={item} />)} 
       </ul> 
       <ButtonToolbar>
         <DeleteRecipeButton deleteRecipe = {this.props.deleteRecipe} recipeName={this.props.recipe.name}/>  
         <EditRecipeButton editRecipe = {this.props.editRecipe} recipe={this.props.recipe}/>  
       </ButtonToolbar>  
        </div>  
      </li>


    )


}

});

var IngredientItem = function(props){

  return (
  <li className="list-group-item">

    <p>{props.ingredient}</p>
  </li>


  )

};


var EditRecipeButton = React.createClass({

  render: function(){

   return (

     <Button bsStyle="default" bsSize="small" onClick={() => this.props.editRecipe(this.props.recipe)}>Edit</Button>  

   ) 

  }


});


var AddRecipe = React.createClass({
//Form in modal to add recipe

  getInitialState(){

    return {

     name: this.props.initialFormInput.name, 

     ingredients: this.props.initialFormInput.ingredients


    };

  },


  getValidationStateName(){

    var length = this.state.name.length;

    if(length > 0) {

      return "success";

    } else {

      return "error";

    }

  },

  getValidationStateIngredients(){

    var length = this.state.ingredients.length;

    if(length > 0){

      return "success";

    } else {

      return "error";

    }


  },

  handleInput: function(key,e){

    var input = e.target.value;


    if(key === "ingredients"){

        input = e.target.value.split(",");  

    }

    var update = {};

    update[key] = input;

    this.setState(update, function(){

      console.log(this.state);

    });


  }, 

 handleSubmit(){

   var recipe = JSON.stringify({name: this.state.name, ingredients: this.state.ingredients});

   localStorage.setItem(this.state.name, recipe);

   var recipeObject= JSON.parse(recipe);

   this.props.addRecipeKey(recipeObject);

   this.props.closeModal();

   this.setState({name: "", ingredients: []});


  },

  render: function(){ 

    return (

      <div>
        <Modal show={this.props.showModal} onHide={this.props.closeModal}>
            <Modal.Header closeButton>
              <Modal.Title>Add a Recipe Here</Modal.Title>
            </Modal.Header>
            <Modal.Body>
              <form>
        <FormGroup controlId="formNameText" validationState = {this.getValidationStateName()}>
          <ControlLabel>Recipe</ControlLabel>
          <FormControl
            type="text"
            placeholder="Give your recipe a name"
            value={this.state.name}
            onInput={this.handleInput.bind(this,'name')}
            />
          <FormControl.Feedback /> 
        </FormGroup>  
          <br/>
        <FormGroup controlId="formIngredientsTextarea" validationState = {this.getValidationStateIngredients()}>
          <ControlLabel>Ingredients</ControlLabel>
          <FormControl
            componentClass="textarea"
            placeholder="Insert your ingredients, separated by a comma"
            value={this.state.ingredients}
            onInput={this.handleInput.bind(this,'ingredients')}
          />  
          <FormControl.Feedback /> 
          <hr/>
        </FormGroup>

        <Button bsStyle="primary" onClick={this.handleSubmit}>Submit</Button>
      </form>  
            </Modal.Body>
        </Modal>
      </div>


      )
  }

});


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

});

因此,当父状态发生变化时,这不会改变:

getInitialState(){

    return {

     name: this.props.initialFormInput.name, 

     ingredients: this.props.initialFormInput.ingredients


    };

  },  

2 个答案:

答案 0 :(得分:2)

顾名思义,getInitialState仅提供组件的初始状态。后续更新不会触发该功能。

您需要实现componentWillReceiveProps以更新道具更改时的状态。来自docs

  在挂载的组件接收新道具之前调用

componentWillReceiveProps()。如果您需要更新状态以响应prop更改(例如,重置它),您可以比较this.propsnextProps并使用此方法中的this.setState()执行状态转换。 / p>      

请注意,即使道具没有更改,React也可以调用此方法,因此如果您只想处理更改,请确保比较当前值和下一个值。当父组件导致组件重新渲染时,可能会发生这种情况。

答案 1 :(得分:0)

如果您想跨组件共享状态,请使用redux。还为每个组件维护一个单独的文件。 此链接可能对您有所帮助 Step by Step Guide To Building React Redux Apps