【问题标题】:Trouble with component re-rendering in basic React app基本 React 应用程序中组件重新渲染的问题
【发布时间】:2017-05-12 05:57:10
【问题描述】:

我正在构建一个基本的 React 应用程序,它从数组中呈现书籍列表,并具有将另一个书籍对象推送到数组的表单。我在想修改 book 数组是对 props 的更改,这将导致 Post 组件重新渲染,但我无法让 Post 重新渲染,除非我通过点击链接手动强制它和导航回来。我相信我已经附上了所有相关的组件以及书籍阵列。我使用 create-react-app 来设置 React 环境。 React 版本 - 15.4.1。 非常感谢您提供的任何帮助!

编辑: 我已经进行了一些重构并创建了一个 github repo 以使一切更加清晰。

Github Repo

import React from 'react'
import ReactDOM from 'react-dom'
import {Router, Route, IndexRoute, hashHistory} from 'react-router'

import App from './App'
import Display from './Display'
import Content from './Content'

//stylesheet
import './index.css'

//import posts array
import postsArray from './postsArray'

ReactDOM.render(
  <Router history={hashHistory}>
    <Route path="/" component={App}>
      <IndexRoute component={Display} entries={postsArray}></IndexRoute>
      <Route path="view/:id" component={Content} entries={postsArray}></Route>
    </Route>
  </Router>,
  document.getElementById('root')
);

import React, {Component} from 'react'

import Post from './Post'


class Display extends Component {

  constructor(props) {
    super(props)
    this.handleSubmit = this.handleSubmit.bind(this)
  }

  handleSubmit(event) {
    this.props.route.entries.push({
      title: this.titleInput.value,
      author: this.authorInput.value,
      body: this.bodyText.value
    })
    event.preventDefault()
  }


  render() {
    return(
      <div>
        <Post entries={this.props.route.entries}/><br /> <br />
        <form onSubmit={this.handleSubmit}>
          <label>
            Title:<br />
            <input type={"text"} ref={(titleInput) => this.titleInput = titleInput}  className="input" />
          </label><br />
          <label>
            Author:<br />
            <input type="text" ref={(authorInput) => this.authorInput = authorInput} className="input" />
            </label> <br />
          <label>
            Body:<br />
            <textarea ref={(bodyText) => this.bodyText = bodyText} className="textAreaInput"/>
          </label> <br />
          <input type="submit" value="Submit" />
        </form>
      </div>
    )
  }
}

export default Display

import React, {Component} from 'react'
import {Link} from 'react-router'


class Post extends Component {
  constructor(props) {
    super(props)
    console.log("insinde post initial", this.props.entries)
  }
  render() {
    return (
      <div className="postsWrapper">
        {this.props.entries.map((entry, index) => (
          <div key={index} className="divMargin">
            <Link to={"view/" + index } className="postLink">
                <h1 className="postH titleFont">{entry.title}</h1>
                <h2 className="authorFont authorMargin">{entry.author}</h2>
            </Link>
          </div>
        ))}
      </div>
    )
  }
}

export default Post

var posts = [
  {
    title: "A Walk in the Woods",
    author: "Bill Bryson",
    body: "A very enjoyable book!"
  },
  {
    title: "Bridge Over The River Kwai",
    author: "Pierre Boulle",
    body: "I have never read this book. Not ever."
  },
  {
    title: "Do Not Sell at Any Price",
    author: "Amanda Petrusich",
    body: "Will you please please please give me this book when you're done?"
  },
  {
    title: "Just Kids",
    author: "Patti Smith",
    body: "This is a national book award winner! Wow!"
  }
]

export default posts

【问题讨论】:

  • 在路由器上使用“条目”对我来说有点不常见。您能进一步解释一下为什么要以这种方式填充帖子数组吗?
  • 而且,既然您正在记录帖子数组,那么您的数组道具可以在帖子组件中成功更新吗?
  • 我有点武断地决定将数组作为道具从路由器传递。这可能不是最好的决定,但即使我将条目作为显示组件的道具传递,我也会遇到同样的问题。此外 Post 组件实际上只负责渲染每个 Post 并且它与发生更新的表单断开连接,但我觉得它仍然应该重新渲染,因为 props 发生了变化。

标签: javascript reactjs


【解决方案1】:

默认情况下,如果 props(在您的情况下是 posts 数组)发生变化,相关组件应该会顺利更新。

但是由于你的Post组件拒绝更新,我建议你使用shouldComponentUpdate()进行检查,检查props是否有相应的更新。

shouldComponentUpdate 总是在渲染方法之前调用,并且可以定义是否需要重新渲染或可以跳过。

componentWillUpdate 一旦 shouldComponentUpdate 返回 true 就会被调用。不允许通过 this.setState 进行任何状态更改,因为此方法应严格用于为即将到来的更新做准备,而不是触发更新本身。

如果您不熟悉生命周期方法,请查看此article

你的情况,试试

shouldComponentUpdate(nextProps, nextState) {
  return nextProps.entries.length !== this.props.entries.length;
}

componentWillUpdate(nextProps, nextState) {
  // posts array did change, do something
}

【讨论】:

  • 感谢您的帮助!我尝试实现不触发重新渲染的 shouldComponentUpdate 方法。我在 return 上方放置了一个 console.log,只是为了查看它何时被调用,但无法记录任何内容,就好像 shouldComponentUpdate 从未被调用过一样。
  • @HarryZumwalt 这意味着你的道具和状态都没有改变;很可能是您通过路由器获得的道具没有相应更新。尝试一种获取帖子数组的新方法 - 我建议使用 componentWillMount() 生命周期方法从 Redux store 获取数组。
  • 嗯,很有趣。我已经尝试通过 Display(不是路由器)直接通过道具将其引入。我还尝试将状态设置为等于构造函数/componentWillMount 挂钩内的数组,但没有成功。我确信 Redux 不是必需的。对此感到困惑。
【解决方案2】:

我能够通过使用setState.concat 而不是直接使用.push 改变数组来解决这个问题(并学到一些东西)。最终的解决方案是这样的:

this.setState({
  entries: this.state.entries.concat([{
    title: this.titleInput.value,
    author: this.authorInput.value,
    body: this.bodyText.value
  }])
})

如果有兴趣,实际更改在 github 存储库中。

感谢@Stanley Luo 在调试方面的帮助。

【讨论】:

    猜你喜欢
    • 2022-10-21
    • 1970-01-01
    • 2020-07-24
    • 2020-12-05
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 2021-06-19
    • 2018-04-22
    相关资源
    最近更新 更多