Redux React-Bootstrap Collapsible Panel issue

时间:2016-08-30 04:46:57

标签: twitter-bootstrap reactjs redux react-redux collapsable

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);

1 个答案:

答案 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);