So I've basically finished one of FCC's RecipeBox Project
The only thing I am having trouble is to keep track of the panel's collapse state.
In other words, every time I change the app's state (whether from adding, deleting, or editing a recipe), it re-renders the page and every panel uncollapse it.
I've taken look at the React-Bootstrap Document but I cannot figure it out.
My current code does not work when applying a state for each recipe items
src/containers/recipebox
class RecipeBox extends Component {
constructor(props){
super(props);
this.state = {open: false}
this.renderRecipeList = this.renderRecipeList.bind(this)
this.handleRecipeNameChange = this.handleRecipeNameChange.bind(this)
this.handleUserIngredientsChange = this.handleUserIngredientsChange.bind(this)
}
handleRecipeNameChange(event){
this.setState({recipeName: event.target.value})
}
handleUserIngredientsChange(event){
this.setState({userIngredients: event.target.value})
}
renderRecipeList(recipeItem, index){
const recipe = recipeItem.recipe;
const ingredients = recipeItem.ingredients;
const recipeID = recipeItem.id;
const id = shortid.generate();
return(
<div key={id}>
<Panel
collapsible
onClick={ ()=> this.setState({ open: !this.state.open })}
eventKey={index}
header={<h3>{recipe}</h3>}>
<ListGroup >
<ListGroupItem header="Ingredients"></ListGroupItem>
{ingredients.map(function(ingredient,index){
return <ListGroupItem key={index}>{ingredient}</ListGroupItem>;
})}
<ListGroupItem>
<Button
onClick={() => this.props.deleteRecipe(recipeItem)}
bsStyle="danger">Delete
</Button>
<Edit
recipeName={recipe}
userIngredients={ingredients}
recipeID={recipeID}
/>
</ListGroupItem>
</ListGroup>
</Panel>
</div>
)
}
render(){
const self = this;
return(
<div className="container">
<div className='panel-group'>
{this.props.recipeList.map(self.renderRecipeList)}
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
recipeList : state.recipeState
};
}
function mapDispatchToProps(dispatch){
return bindActionCreators({deleteRecipe : deleteRecipe, editRecipe : editRecipe}, dispatch)
}
export default connect(mapStateToProps,mapDispatchToProps)(RecipeBox);
答案 0 :(得分:0)
所以我能够找出问题所在:我需要每个配方都有自己的组件状态。
我创建了一个单独的组件 RecipeList ,它可以呈现每个配方项,还有自己的状态组件。
我修改如下:
<强>的src /容器/ recipebox 强>
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ListGroup, ListGroupItem, Panel, Button, Modals } from 'react-bootstrap';
import RecipeList from '../containers/recipe_list'
class RecipeBox extends Component {
constructor(props){
super(props);
}
render(){
let itemList = [];
this.props.recipeList.forEach(function(item){
itemList.push(
<RecipeList
key={item.id}
recipeID={item.id}
recipe={item.recipe}
ingredients={item.ingredients}
/>)
})
return(
<div className="container">
<div className='panel-group'>
{itemList}
</div>
</div>
)
}
}
function mapStateToProps(state) {
return {
recipeList : state.recipeState
};
}
export default connect(mapStateToProps)(RecipeBox);
<强>的src /容器/ recipe_list 强>
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ListGroup, ListGroupItem, Panel, Button, Modals } from 'react-bootstrap';
import { bindActionCreators } from 'redux';
import { deleteRecipe, editRecipe } from '../actions/index';
import shortid from 'shortid'
import Edit from '../containers/edit_recipe'
class RecipeList extends Component {
constructor(props){
super(props);
this.state = {open: false}
}
handleRecipeNameChange(event){
this.setState({recipeName: event.target.value})
}
handleUserIngredientsChange(event){
this.setState({userIngredients: event.target.value})
}
render(){
return(
<div>
<Panel
collapsible
header={<h3>{this.props.recipe}</h3>}>
<ListGroup >
<ListGroupItem header="Ingredients"></ListGroupItem>
{this.props.ingredients.map(function(ingredient,index){
return <ListGroupItem key={index}>{ingredient}</ListGroupItem>;
})}
<ListGroupItem>
<Button
onClick={() => this.props.deleteRecipe(this.props.recipeID)}
bsStyle="danger">Delete
</Button>
<Edit
recipeName={this.props.recipe}
userIngredients={this.props.ingredients}
recipeID={this.props.recipeID}
/>
</ListGroupItem>
</ListGroup>
</Panel>
</div>
)
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({deleteRecipe, editRecipe}, dispatch)
}
export default connect(null,mapDispatchToProps)(RecipeList);