2016-12-28 43 views
0

我正在構建一個基本的React應用程序,該應用程序呈現數組中書籍的列表,並具有將另一個書籍對象推送到數組的表單。我在考慮修改book數組是對道具的一種改變,這會導致Post組件重新渲染,但是我不能讓Post重新渲染,除非我強制使用鏈接和導航回來手動強制它。我相信我已經附加了所有相關的組件以及書籍數組。我使用create-react-app來設置React環境。 React版本 - 15.4.1。非常感謝您提供的任何幫助!在基本的React應用程序中重新渲染組件的問題

編輯: 我已經重構了一點,創造了一個GitHub庫,使一切更清晰。

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

+0

在路由器上使用「條目」對我來說看起來有點不尋常。你能否進一步解釋爲什麼你想以這種方式填充帖子數組? –

+0

而且,由於您正在記錄帖子數組,您的數組道具可以在Post組件中成功更新嗎? –

+0

我有點擅自決定從路由器傳遞陣列作爲道具。這可能不是最好的決定,但即使我通過顯示組件中的道具作爲道具,也會遇到同樣的問題。另外,Post組件實際上只負責渲染每個Post,並且這些內容與更新發生的形式沒有關係,但是我覺得它應該仍然會因道具變化而重新渲染。 –

回答

0

我能解決這個問題(和學習的東西)通過使用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對他的調試幫助。

1

默認情況下,如果道具(在你的情況,帖子陣列)的變化,相關的組件應無故障更新。

但由於您的Post組件拒絕更新,我建議您使用shouldComponentUpdate()進行檢查,檢查道具是否相應更新。

shouldComponentUpdate總是在render方法之前被調用,並且能夠定義是否需要重新渲染或可以跳過。

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 
} 
+0

感謝您的幫助!我試着實現了不會觸發重新渲染的shouldComponentUpdate方法。我在回車上面放了一個console.log,以查看它何時被調用,但無法獲取任何日誌,就好像shouldComponentUpdate從未被調用過。 –

+0

@HarryZumwalt這意味着你的道具和狀態都不會改變;很可能它是通過路由器獲得的道具沒有相應更新。嘗試一種獲取posts數組的新方法 - 我推薦使用'componentWillMount()'生命週期方法從'Redux store'中獲取數組。 –

+0

嗯有趣。我已經嘗試直接通過「Display」(不是路由器)通過道具引入它。我也試着設置狀態等於構造函數/ componentWillMount掛鉤內的數組,但沒有成功。我確定Redux不應該是必需的。難住這個。 –