2017-11-25 108 views
0

我試圖製作一個反應消息應用程序,其中的通道頁面由一個通道欄Channel.js(父組件)和一個通用和隨機通道以及消息列表ChannelMessage.js(子組件)。在父狀態改變後反應子組件未更新

目前,我可以點擊通道欄,它會更改url和this.props.channelName,但子組件顯示相同的文本,而不管Link單擊。我相信這是因爲ComponentDidMount沒有在子組件中調用。我將如何去更新/重新渲染子組件來獲取ComponentDidMount來重新加載?

Channel.js

export default class Channel extends React.Component { 
constructor(props) { 
    super(props); 
    this.state = { 
     channelName: 'general' 
    }; 
    this.handleSignOut = this.handleSignOut.bind(this); 
} 

... 

render() { 
    return (
     <div className="container"> 
      <div className="row"> 
       <div className="channel-list col-lg-2"> 
        <h2>Channels</h2> 
        <ul className="list-group"> 
         <li><Link to="/channel/general" 
          onClick={() => this.setState({ channelName: 'general' })}>General</Link></li> 
         <li><Link to="/channel/random" 
          onClick={() => this.setState({ channelName: 'random' })}>Random</Link></li> 
        </ul> 
        <div className="footer-segment"> 
         ... 
        </div> 
       </div> 
       <ChannelMessages channelName={this.state.channelName} /> 
      </div> 
     </div> 
    ); 
} 

ChannelMessages.js

export default class ChannelMessages extends React.Component { 
constructor(props) { 
    super(props); 
    this.state = { 
     channelName: this.props.channelName, 
     message: '', 
     messages: [], 
     textValue: '' 
    } 
    ... 
} 

componentWillReceiveProps(nextProps) { 
    this.setState({channelName: nextProps.channelName}) 
} 

componentDidMount() { 
    this.messageRef = firebase.database().ref('messages/' + this.state.channelName); 
    this.messageRef.limitToLast(500).on('value', (snapshot) => { 
     let messages = snapshot.val(); 
     if (messages !== null) { 
      let newMessages = []; 
      for (let message in messages) { 
       newMessages.push({ 
        author: { 
         displayName: messages[message].author.displayName, 
         photoURL: messages[message].author.photoURL, 
         uid: messages[message].author.uid 
        }, 
        body: messages[message].body, 
        createdAt: messages[message].createdAt, 
        id: message 
       }); 
      } 
      this.setState({ messages: newMessages, textValue: newMessages.body }); 
     } 
     console.log(this.state.textValue) 
    }); 
} 

componentWillUnmount() { 
    this.messageRef.off('value'); 
} 

handleSubmitMessage(event) { 
    event.preventDefault(); 
    let user = firebase.auth().currentUser; 
    this.messageRef.push().set({ 
     author: { 
      displayName: user.displayName, 
      photoURL: user.photoURL, 
      uid: user.uid 
     }, 
     body: this.state.message, 
     createdAt: firebase.database.ServerValue.TIMESTAMP 
    }); 
    this.setState({ message: '' }); 
} 

... 

render() { 
    return (...); 
} 

}

+0

使用componentWillreceiveProps更新生命週期方法。 – stack26

回答

0

你爲什麼不直接使用的頻道名稱從道具?您正在使用componentDidMount事件。它只運行一次。如果您想在新的頻道名稱通過時運行Firebase代碼,提取取邏輯功能和componentDidMount和componentDidUpate運行它(點擊此處查看它是否與以前的不同)

ComponentDidMount只運行一次 - more here

- more here

ComponentDidUpdate不會在初始觸發運行

export default class ChannelMessages extends React.Component { 
    constructor(props) { 
     super(props); 
     this.state = { 
      message: '', 
      messages: [], 
      textValue: '' 
     } 
     ... 
    } 

    componentDidMount() { 
     const {channelName} = this.props; 

     fetchFromDb(channelName); 
    } 

    componentDidUpdate(prevProps) { 
     if (prevProps.channelName !== this.props.channelName) { 
      fetchFromDb(this.props.channelName);    
     } 
    } 

    componentWillUnmount() { 
     this.messageRef.off('value'); 
    } 

    handleSubmitMessage(event) { 
     event.preventDefault(); 
     let user = firebase.auth().currentUser; 
     this.messageRef.push().set({ 
      author: { 
       displayName: user.displayName, 
       photoURL: user.photoURL, 
       uid: user.uid 
      }, 
      body: this.state.message, 
      createdAt: firebase.database.ServerValue.TIMESTAMP 
     }); 
     this.setState({ message: '' }); 
    } 

    ... 

    render() { 
     return (...); 
    } 
}