class App extends Component {
constructor(props) {
super(props)
this.state = { text: "", messages: [] }
}
componentDidMount() {
const config = {
apiKey: "<api-key>",
authDomain: "<project-name>.firebaseapp.com",
databaseURL: "https://<project-name>.firebaseio.com",
projectId: "<project-name>",
storageBucket: "<project-name>.appspot.com",
messagingSenderId: "<sender-id>",
};
if (!firebase.apps.length) {
firebase.initializeApp(config);
}
this.getMessages()
var database = firebase.database();
var ref = database.ref('messages');
}
onSubmit = event => {
if (event.charCode === 13 && this.state.text.trim() !== "") {
this.writeMessageToDB(this.state.text)
this.setState({ text: "" })
}
}
writeMessageToDB = () => {
firebase.database().ref('messages/').push({
text: this.state.text,
createdAt: createdAt,
user:{
_id: currentUser,
name:name
}
});
}
getMessages = () => {
var messagesDB = firebase
.database()
.ref("messages/")
.limitToLast(500)
messagesDB.on("value", snapshot => {
let newMessages = []
snapshot.forEach(child => {
var message = child.val()
var yeah = dateFormat(message.createdAt,"dddd, mmmm dS, yyyy, h:MM:ss TT")
newMessages.push({ id: child.key, text: message.text,createdAt: yeah, names: message.name })
})
this.setState({ messages: newMessages })
this.bottomSpan.scrollIntoView({ behavior: "smooth" })
})
}
renderMessages = () => {
return this.state.messages.map(message => (
<ListItem>
<ListItemText className="chatList"
style={{ wordBreak: "break-word", backgroundColor: "#FFA1B5", borderRadius: "10px", width: "10px", padding: "5px" }}
primary={message.name+": "+message.text}
secondary={message.createdAt}
/>
</ListItem>
))
}
render() {
return (
<MuiThemeProvider theme={theme}>
<div style={mainCont}>
<label style={labelStyle} className="labelStyle"> Chat</label>
<div className="App" >
<ScrollToBottom className={ ROOT_CSS }>
<List>{this.renderMessages()}</List>
</ScrollToBottom>
<TextField className="txtFieldStyle"
autoFocus={true}
multiline={true}
rowsMax={3}
placeholder="Type something.."
onChange={event => this.setState({ text: event.target.value })}
value={this.state.text}
onKeyPress={this.onSubmit}
style={{ width: "350px", overflow: "hidden", marginLeft: "15px", fontSize: '63px', paddingBottom: '5px' }}
/>
<span ref={el => (this.bottomSpan = el)} />
</div>
</div>
</MuiThemeProvider>
)
}
}
export default App;
除非用户导航到其他页面并返回到聊天功能并尝试通过聊天发送消息,否则聊天功能才能正常工作。
答案 0 :(得分:1)
App.componentDidMount()
中的以下两行是潜在的竞争条件。
this.setState({ messages: newMessages })
this.bottomSpan.scrollIntoView({ behavior: "smooth" })
App
状态可能会更早突变,以开始渲染周期,以便将bottomSpan
设置为在调用this.bottomSpan.scrollIntoView()
之前引用元素。
但是,永远不能保证在状态更新后调用this.bottomSpan.scrollIntoView()
。
请记住,setState
并不总是立即改变组件的状态。 [1]
在状态被突变后,您可以在作为状态的第二个参数传递的回调中进行操作,从而将引用的元素滚动到视图中。
this.setState(
{ messages: newMessages },
() => this.bottomSpan.scrollIntoView({ behavior: "smooth" })
)