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;
除非用户导航到其他页面并返回到聊天功能并尝试通过聊天发送消息,否则聊天功能将正常工作。
最佳答案
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" })
)
关于javascript - TypeError:无法读取null的属性'scrollIntoView',我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/53993583/