【问题标题】:React.js not re-rendering app on state updateReact.js 不会在状态更新时重新渲染应用程序
【发布时间】:2017-06-21 16:08:54
【问题描述】:

我正在开发基于 React.js 的大纲(类似于工作流)。我被困在一个点上。当我在任何一项上按 Enter 键时,我想在其下方插入另一项。

所以我使用 setState 函数在当前项目的下方插入一个项目,如下面的代码 sn-p 所示:

 this.setState({
      items: this.state.items.splice(this.state.items.map((item) => item._id).indexOf(itemID) + 1, 0, {_id: (new Date().getTime()), content: 'Some Note'})
 })

但是,应用程序重新呈现为空白,没有出现任何错误。

到目前为止我的完整来源:

import './App.css';

import React, { Component } from 'react';
import ContentEditable from 'react-contenteditable';

const items = [
  {
    _id: 0,
    content: 'Item 1 something',
    note: 'Some note for item 1'
  },
  {
    _id: 5,
    content: 'Item 1.1 something',
    note: 'Some note for item 1.1'
  },
  {
    _id: 1,
    content: 'Item 2 something',
    note: 'Some note for item 2',
    subItems: [
      {
        _id: 2,
        content: 'Sub Item 1 something',
        subItems: [{
          _id: 3,
          content: 'Sub Sub Item 4'
        }]
      }
    ]
  }
];

class App extends Component {
  render() {
    return (
      <div className="App">
        <Page items={items} />
      </div>
    );
  }
}

class Page extends Component {
  constructor(props) {
    super(props);

    this.state = {
      items: this.props.items
    };

    this.insertItem = this.insertItem.bind(this);
  }

  render() {
    return (
      <div className="page">
        {
          this.state.items.map(item =>
            <Item _id={item._id} content={item.content} note={item.note} subItems={item.subItems} insertItem={this.insertItem} />
          )
        }
      </div>
    );
  }

  insertItem(itemID) {
    console.log(this.state.items);

    this.setState({
      items: this.state.items.splice(this.state.items.map((item) => item._id).indexOf(itemID) + 1, 0, {_id: (new Date().getTime()), content: 'Some Note'})
    })

    console.log(this.state.items);
  }
}

class Item extends Component {
  constructor(props) {
    super(props);

    this.state = {
      content: this.props.content,
      note: this.props.note
    };

    this.saveItem = this.saveItem.bind(this);
    this.handleKeyPress = this.handleKeyPress.bind(this);
  }

  render() {
    return (
      <div key={this.props._id} className="item">
        <ContentEditable html={this.state.content} disabled={false} onChange={this.saveItem} onKeyPress={(event) => this.handleKeyPress(this.props._id, event)} />

        <div className="note">{this.state.note}</div>
        {
          this.props.subItems &&
          this.props.subItems.map(item =>
            <Item _id={item._id} content={item.content} note={item.note} subItems={item.subItems} insertItem={this.insertItem} />
          )
        }
      </div>
    );
  }

  saveItem(event) {
    this.setState({
      content: event.target.value
    });
  }

  handleKeyPress(itemID, event) {
    if (event.key === 'Enter') {
      event.preventDefault();
      console.log(itemID);
      console.log(event.key);
      this.props.insertItem(itemID);
    }
  }
}

export default App;

github 仓库:https://github.com/Hirvesh/mneme

谁能帮我理解为什么在我更新项目后它没有再次呈现?

编辑:

我已更新代码以添加键,如下所示,尽管状态更新,但仍呈现为空白:

import './App.css';

import React, { Component } from 'react';
import ContentEditable from 'react-contenteditable';

const items = [
  {
    _id: 0,
    content: 'Item 1 something',
    note: 'Some note for item 1'
  },
  {
    _id: 5,
    content: 'Item 1.1 something',
    note: 'Some note for item 1.1'
  },
  {
    _id: 1,
    content: 'Item 2 something',
    note: 'Some note for item 2',
    subItems: [
      {
        _id: 2,
        content: 'Sub Item 1 something',
        subItems: [{
          _id: 3,
          content: 'Sub Sub Item 4'
        }]
      }
    ]
  }
];

class App extends Component {
  render() {
    return (
      <div className="App">
        <Page items={items} />
      </div>
    );
  }
}

class Page extends Component {
  constructor(props) {
    super(props);

    this.state = {
      items: this.props.items
    };

    this.insertItem = this.insertItem.bind(this);
  }

  render() {
    return (
      <div className="page">
        {
          this.state.items.map(item =>
            <Item _id={item._id} key={item._id} content={item.content} note={item.note} subItems={item.subItems} insertItem={this.insertItem} />
          )
        }
      </div>
    );
  }

  insertItem(itemID) {
    console.log(this.state.items);

    this.setState({
      items: this.state.items.splice(this.state.items.map((item) => item._id).indexOf(itemID) + 1, 0, {_id: (new Date().getTime()), content: 'Some Note'})
    })

    console.log(this.state.items);
  }
}

class Item extends Component {
  constructor(props) {
    super(props);

    this.state = {
      content: this.props.content,
      note: this.props.note
    };

    this.saveItem = this.saveItem.bind(this);
    this.handleKeyPress = this.handleKeyPress.bind(this);
  }

  render() {
    return (
      <div className="item">
        <ContentEditable html={this.state.content} disabled={false} onChange={this.saveItem} onKeyPress={(event) => this.handleKeyPress(this.props._id, event)} />

        <div className="note">{this.state.note}</div>
        {
          this.props.subItems &&
          this.props.subItems.map(item =>
            <Item _id={item._id} key={item._id} content={item.content} note={item.note} subItems={item.subItems} insertItem={this.insertItem} />
          )
        }
      </div>
    );
  }

  saveItem(event) {
    this.setState({
      content: event.target.value
    });
  }

  handleKeyPress(itemID, event) {
    if (event.key === 'Enter') {
      event.preventDefault();
      console.log(itemID);
      console.log(event.key);
      this.props.insertItem(itemID);
    }
  }
}

export default App;

编辑 2:

按照下面的建议,加了key={i._id},还是不行,把最新的代码推到github上,如果有人想看的话。

  this.state.items.map((item, i) =>
    <Item _id={item._id} key={i._id} content={item.content} note={item.note} subItems={item.subItems} insertItem={this.insertItem} />
  )

【问题讨论】:

  • 如果您格式化代码并使其更具可读性,这将更容易提供帮助。如果可能,您还可以删除任何未使用的代码。
  • 单独查看长不可读的代码行:const newItems = this.state.items.splice(this.state.items.map((item) =&gt; item._id).indexOf(itemID) + 1, 0, {_id: (new Date().getTime()), content: 'Some Note'})this.setState({items: newItems})
  • 我做到了,项目状态对象更新得很好,项目已添加,但应用程序重新呈现为空白
  • 但是splice的第一个参数不是数组,所以不可能对。
  • 哦,我看到最后有 indexOf..

标签: javascript reactjs ecmascript-6


【解决方案1】:

您的代码存在多个问题:

  1. 在您将this.insertItem 传递到子项(不存在)中
  2. 您的this.state.items.splice,更改this.state.items,但返回[]。所以你的新状态是[]

试试这个:

this.state.items.splice(/* your splice argument here */)
this.setState({ items: this.state.items }, () => {
  // this.setState is async! so this is the proper way to check it.
  console.log(this.state.items);
});

要完成你真正想要的,这还不够。但至少,当你修复它时,你可以看到一些结果。

【讨论】:

  • 谢谢!我相信我的方向是正确的。试图把事情做对,会更新一些:)
  • 知道拼接不工作的原因吗?我不明白为什么它在拼接时返回一个空数组...
  • 哦,我智障了。 “splice()”函数返回的不是受影响的数组,而是删除元素的数组。如果不删除任何内容,则结果数组为空。
  • 对于数组操作,最好使用slice(),它返回一个新数组,它是不可变的样式。
【解决方案2】:

你错过了在 Item 上放一个键,因为 React 无法识别你的状态是否改变。

<div className="page">
{
  this.state.items.map((item, i) =>
     <Item _id={item._id} 
      key={i} // <---- HERE!!
      content={item.content} 
      note={item.note} 
      subItems={item.subItems} 
      insertItem={this.insertItem} />     
  )}
</div>

【讨论】:

  • 我添加了密钥,但是状态更新了,但仍然没有重新渲染:/
  • 不是这里的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-29
  • 2017-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
相关资源
最近更新 更多