javascript - react : setting state based on local storage

标签 javascript reactjs dom components

当我运行此代码时,我会为本地存储内的每个配方项获得一个引导面板组。当我尝试删除菜谱时,有时正确的菜谱会被删除,有时则不会。控制台显示正确的配方已从本地存储中删除,但由于某种原因,当应用程序组件重置其状态时,错误的配方被删除。我注意到,如果我尝试从下往上删除食谱,它会起作用。但如果我点击第一个菜谱,底部的菜谱就会被删除。

我知道这是一个简单的解决方案,但我需要一个新的视角。感谢大家! 另外,抱歉代码中缺少缩进 - 堆栈溢出对间距不太友好

class App extends Component {
  constructor() {
  super();
  this.deleteRecipe = this.deleteRecipe.bind(this)
  this.state = {
    recipeData: JSON.parse(localStorage.getItem('recipeData'))
 }
}

deleteRecipe() {
this.setState({recipeData: JSON.parse(localStorage.getItem('recipeData'))})
}

render() {
 return (
  <div className="App">
    <div className="App-header">
      <img src={logo} className="App-logo" alt="logo" />
      <h2>Welcome to React Recipe Box!</h2>
    </div>

    <div className="container">
      {this.state.recipeData.map(recipe => {
        return (
        <Recipe name={recipe.name} ingredients={recipe.ingredients} deleteRecipe={this.deleteRecipe}/>
        )
      })}
    </div>
  </div>
);
}
}

class Recipe extends Component {
 constructor() {
 super();
  this.onDeleteRecipe = this.onDeleteRecipe.bind(this)
 }

componentWillMount(){   //set state when component is about to mount
this.state = {
  name: this.props.name,
  ingredients: this.props.ingredients,

}
}

onDeleteRecipe() {
var recipeList = JSON.parse(localStorage.getItem('recipeData'));
for(var i = 0; i < recipeList.length; i++) {
  if(recipeList[i].name === this.state.name) {
    recipeList.splice(i, 1);
    console.log("Deleted " + this.state.name, recipeList);
    localStorage.removeItem('recipeData');
    localStorage.setItem('recipeData', JSON.stringify(recipeList));

    this.props.deleteRecipe();
  }
 }

}

 render() {
 return (
 <div>
  <div className="panel-group">
    <div className="panel panel-primary">
      <div className="panel-heading">
        <h2 className="panel-title">
          <a data-toggle="collapse" data-target={'#' + (this.state.name).replace(/\s/g, '')} href={'#' + (this.state.name).replace(/\s/g, '')}>
             {this.state.name}
          </a>
        </h2>>              
      </div>
     <div id={(this.state.name).replace(/\s/g,'')} className="panel-collapse collapse">
      <div className="panel-body"> 
          {this.state.ingredients.map(ingredient => {
            return <li className="list-group-item">{ingredient}</li>
          })}
          <div className="btn-group">
            <button className="btn btn-sm btn-info" data-toggle="modal" 
                    data-target={'#' + (this.state.name).replace(/\s/g, '') + 'EditModal'}>Edit</button>
            <button className="btn btn-sm btn-danger" data-toggle="modal"
                    data-target={'#' + (this.state.name).replace(/\s/g, '') + 'RemoveModal'}
                    >Delete</button>
          </div>
      </div>
     </div>
    </div>
  </div>


    <div className="modal modal-lg" id={(this.state.name).replace(/\s/g, '') + 'EditModal'} >
        <div className="modal-content">
          <div className="modal-header">
            <h2>Edit {this.state.name}</h2>
          </div>
          <div className="modal-body">
            <ul className="list-group list-unstyle">
              {this.state.ingredients.map( ingredient => {
                return <li className="list-group-item">{ingredient}</li>
              })}
            </ul>
          </div>
          <div className="modal-footer">
            <div className="btn-group">
              <button className="btn btn-sm btn-info"  data-dismiss="modal">Save</button>
              <button className="btn btn-sm btn-danger" data-dismiss="modal">Close</button>
            </div>
          </div>
        </div>
      </div>


      <div className="modal modal-lg" id={this.state.name.replace(/\s/g, '') + 'RemoveModal'}>
        <div className="modal-content">
          <div className="modal-body">
            <h3>This will remove the selected recipe. Are you sure?</h3>
          </div>
          <div className="modal-footer">
            <div className="btn-group">
              <button className="btn btn-sm btn-danger" data-dismiss="modal" onClick={this.onDeleteRecipe}>Delete</button>
              <button className="btn btn-sm btn-info" data-dismiss="modal">Close</button>
            </div>
          </div>
        </div>
      </div>
 </div>
);
}
}

export default App;

最佳答案

我还是个新手,但是......几个月前我为 FreeCodeCamp 构建了一个 react 配方框,所以我只是将它拉出来以将我的删除功能与你的进行比较。

我注意到您对待 localStorage 的方式与我对待 localStorage 的方式不同。 (并不是说我的方法是最好的,甚至是正确的!)我想知道问题是否源于该设计。你的删除函数进入 localStorage 并进行更改,然后运行 ​​setState 来“重新获取”recipeData,如果我没看错的话?

相比之下,我的应用程序从 localStorage 声明了一个变量,并将 this.state.recipeArray 设置为等于该变量。然后我的所有编辑/添加/删除功能都会更改 this.state.recipeArray而不是 localStorage。像这样:

handleDelete: function(e) {
    e.preventDefault();

    var replacementRecipeArray = this.state.recipeArray.filter((recipe) => recipe.title !== e.target.name);
    //dot-filter with ES6 fat-arrow returns all items where title doesn't match the one we clicked; IOW, it removes the one we want to delete

    this.setState({
      recipeArray: replacementRecipeArray
    });

  }

为了将对 this.state.recipeArray 的任何更改返回到 localStorage,我每次渲染页面时都会执行 localStorage.setItem。

render() {
    //first save current array to localstorage - wasn't reliable anywhere else
    localStorage.setItem("_shoesandsocks_recipes", JSON.stringify(this.state.recipeArray));

    //render page
    return (
      <div className="App">
        <div className="recipeContainer"> 
          // etc etc

据我所知,这是一个疯狂的设计,但它确实有效。

关于javascript - react : setting state based on local storage,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41858435/

相关文章:

javascript - IE 中不显眼的伪类和属性选择器模拟

JQuery更新数据-属性

javascript - 如何在 JavaScript 中找到的 div 中获取特定类的元素?

javascript - 分派(dispatch)事件在捕获/冒泡周期的哪个阶段开始?

javascript - 组合不同的方法来计算嵌套列表中的元素

javascript - 禁用和选择在自定义选择选项菜单(Javascript)中不起作用

javascript - 对象数组不按属性排序

reactjs - Apollo 客户端不显示错误信息

javascript - 无法从渲染返回调用访问状态 - 'Cannot read property ' instructionList' of null'

javascript - JavaScript 中的 yield 关键字是什么?