在ReactJS

时间:2015-08-06 15:07:05

标签: javascript reactjs react-jsx

我在查找/概念化如何在ReactJS中创建组件时遇到了麻烦。我把一个小例子放在一起,我有一个膳食计划的顶级组成部分,然后我有另一个组件,用于计划中的每餐。

现在,我想要一个组件,显示用户选择餐饮类别的次数。我在这里掀起了一个小例子。 Meal Plan Example

因此,使用该示例,我想要一个总结用户当前选择的水果和蔬菜数量的组件。我以前的思维方式是,我需要在类别更改的某个地方更改计数,但我认为这应该是不同的,更容易对吗?感觉就像我应该(不知何故?)抓住类别选择框的值并计算它们并在新组件中呈现出来。感觉好像我应该看一下ref文档,但是他们使用了一个非常简单的例子。

不确定正确的方法是什么。

这里也是代码。

JSON

var plan = { 
    "meals": [
      {
        "selectedFood":"",
        "mealName":"breakfast"
      },
      {
        "selectedFood":"",
        "mealName":"lunch"
      },
      {      
        "selectedFood":"",
        "mealName":"dinner"
      },
    ],
    "planOptions": [
      {
        "id":1,
        "category":"fruit",
        "food":"apple"
      },
      {
        "id":2,
        "category":"fruit",
        "food":"pear"
      },
      {
        "id":3,
        "category":"vegetable",
        "food":"carrot"
      },
      {
        "id":4,
        "category":"vegetable",
        "food":"corn"
      }
    ]
};

JSX

var PlanEntryBox = React.createClass({
    getInitialState: function() {
        return {
            plan: {}
        };
    },
    render: function() {
    var planOpts = this.props.plan.planOptions;
    var meals = this.props.plan.meals.map(function(meal) {
            return (
                <MealEntryBox mealEntry={meal} planOptions={planOpts} />
            );
        });
        return (
        <div>
            <h1>Meals</h1>
                <table className="table">
           <thead>
             <tr>
               <th>Meal</th>
               <th>Category</th>
               <th>Food</th>
             </tr>
           </thead>
           <tbody>
             {meals}
           </tbody>
         </table>
         <CategoryCounter />
       </div>
        );
    }
});

var MealEntryBox = React.createClass({
    getInitialState: function() {
        return {
            selectedCategory: null
        };
    },
    categoryChange: function(event) {
        this.setState({selectedCategory: event.target.value});
    },
    render: function() {
        var options = _.uniq(_.pluck(this.props.planOptions, 'category'));
        var categoryOpts = options.map( function(category) {
            return (
                <option>{category}</option>
            );
        });

    var filteredOptions = _.filter(this.props.planOptions, {"category": this.state.selectedCategory});
        var foodOpts = filteredOptions.map( function(option) {
            return (
                <option>{option.food}</option>
            );
        });
        return (
     <tr>
             <td>{this.props.mealEntry.mealName}</td>
       <td>
             <select className="form-control" onChange={this.categoryChange}>
                 <option>Pick one... </option>
         {categoryOpts}
             </select>
       </td>

       <td>
             <select className="form-control" disabled={!this.state.selectedCategory}>
         {foodOpts}
             </select>
       </td>
     </tr>
        );
    }
});


var CategoryCounter = React.createClass({
  render: function() {
    return(
      <div>
        <h3>Counts</h3>
      </div>
    );
  }
});

React.render(
    <PlanEntryBox plan={plan} />,
    document.getElementById('content')
);

HTML

<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.rawgit.com/lodash/lodash/3.0.1/lodash.min.js"></script>
<script src="//fb.me/react-0.13.1.js"></script>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
  <meta charset="utf-8">
  <title>Meal Plan Example</title>
</head>
<body>

  <div id="content">

  </div>

</body>
</html>

1 个答案:

答案 0 :(得分:3)

这是对组件state的相当直接的使用。

您希望在父组件中存储水果计数和蔬菜计数(在您的情况下为PlanEntryBox)。首先更新PlanEntryBox.getInitialState()以添加这些计数器的字段。

getInitialState: function() {
    return {
        plan: {}, 
        fruitCount: 0,
        vegieCount: 0
    };
},

然后,将函数添加到PlanEntryBox组件以处理更新计数:

addFruit: function(){
    this.setState({fruitCount: this.state.fruitCount++});
},
addVegie: function(){
    this.setState({vegieCount: this.state.vegieCount++});
}

(你也可能需要递减计数的方法,但我会把它留给你。)

然后将这些方法的引用传递给每个MealEntryBox组件和props。将第PlanEntryBoxrender行修改为:

<MealEntryBox mealEntry={meal} planOptions={planOpts}
    onFruit={this.addFruit} onVegie={this.addVegie}/>

然后使用onFruit中的onVegieMealEntryBox.categoryChange回调:

categoryChange: function(event) {
    if(event.target.value === 'fruit'){
        this.props.onFruit();
    } else {
        this.props.onVegie();
    }

    this.setState({selectedCategory: event.target.value});
},

(注意:同样,这是一个天真的实现。如果用户取消选择用餐或将类型从一个类别更改为另一个类别,您将需要处理递减值。)

例如,调用onFruit将导致父组件更新其状态(使用setState()中的addFruit()调用)。这将导致React呈现组件,并将新的props传递给其子元素。您可以通过将计数传递给CategoryCounter组件来利用这一事实。

修改CategoryCounterrender()PlanEntryBox函数中使用<CategoryCounter fruits={this.state.fruitCount} vegies={this.state.vegieCount} /> 的行,如下所示:

CategoryCounter

然后在render: function() { <div> <h3>Counts</h3> <ul> <li>Fruits: {this.props.fruits}</li> <li>Vegetables: {this.props.vegies}</li> </ul> </div> } 的渲染方法中,显示这些新道具:

state

总结策略:

  • 使用CategoryCounter在顶级组件中存储计数
  • 将对回调函数的引用传递给子组件
  • 更新回调方法中的状态
  • 将当前状态作为道具传递给CategoryCounter,以便它可以显示计数
  • 依赖React在状态发生变化时重新渲染组件,这会导致新的道具传递给1.Obtain transaction specific information. 2.Obtain your paypal account balance 3.Search your transaction specific information. 4.Search your transactions for items that match specific criteria and display the results ,然后重新渲染并显示其新的道具。

要进一步阅读Callbacks并传递数据 up 组件树,请参阅React Tutorial的第五步:https://facebook.github.io/react/docs/thinking-in-react.html#step-5-add-inverse-data-flow