我和mobx有个问题。事实上,我有一个简单的聊天室,它使用我自己定义的WebSocketService。虽然这个服务用我的API抽象交换,但是聊天本身处理消息的存储。
main.tsx (入口点)
import React from 'react';
import ReactDOM from 'react-dom';
import {App} from './app';
import {createBrowserHistory} from 'history';
import {createStores} from "app/stores";
import {Provider} from "mobx-react";
import {LoggedUserModel} from "app/models";
import {newUUID} from "app/utils/UUID";
// prepare MobX stores
const history = createBrowserHistory();
const rootStore = createStores(history, new LoggedUserModel(newUUID(), 'User'));
ReactDOM.render(
<Provider {...rootStore}>
<App history={history}/>
</Provider>,
document.getElementById('root')
);index.tsx (App)
import * as React from 'react';
import {Router, Route, Switch} from 'react-router';
import { hot } from 'react-hot-loader/root';
import { Chat } from "app/containers/Chat";
// render react DOM
export const App = hot(({history}) => {
return (
<Router history={history}>
<Switch>
<Route path="/" component={Chat}/>
</Switch>
</Router>
);
});Chat.tsx
import * as React from 'react';
import style from './style.css'
import {RouteComponentProps} from 'react-router';
import ChatChannelMessagesList from "app/components/Chat/ChatChannelMessagesListComponent";
import ChatChannelInput from "app/components/Chat/ChatChannelInputComponent";
import {inject, observer} from "mobx-react";
import {STORE_LOGGED_USER, STORE_MESSAGES} from "app/constants";
import {LoggedUserStore, MessagesStore} from "app/stores";
import {newUUID} from "app/utils/UUID";
import {MessageModel} from "app/models";
import WebSocketService from "app/services/webSocketService";
export interface ChatProps extends RouteComponentProps<any> {
[STORE_LOGGED_USER]: LoggedUserStore;
[STORE_MESSAGES]: MessagesStore;
}
export interface ChatState {
WebSocketService: WebSocketService
}
@inject(STORE_LOGGED_USER, STORE_MESSAGES)
@observer
export class Chat extends React.Component<ChatProps, ChatState> {
constructor(props: ChatProps, context: any) {
super(props, context);
this.state = {
WebSocketService: new WebSocketService(event => {
// add the new message to state
this.onMessage(event)
})
}
}
componentDidMount() {
this.state.WebSocketService.connect(this.props[STORE_LOGGED_USER].getLoggedUser.id)
}
componentWillUnmount() {
this.state.WebSocketService.disconnect(this.props[STORE_LOGGED_USER].getLoggedUser.id)
}
addMessageToScreen(message: string) {
// add the new message to state
this.props[STORE_MESSAGES].addMessage(new MessageModel(newUUID(), message));
console.log(this.getMessages())
}
onMessage(event) {
console.log(event.data);
this.addMessageToScreen(event.data)
}
sendMessage(input: string) {
this.addMessageToScreen(input);
this.state.WebSocketService.message(this.props[STORE_LOGGED_USER].getLoggedUser.id, input)
}
getMessages() {
return this.props[STORE_MESSAGES].getMessages
}
render() {
return (
<div id={"chat"} className={style.container}>
<div className="rox">
<div className="row-offset-11 row-11 row-sm-11 row-md-11 row-lg-11 row-xl-11">
<ChatChannelMessagesList messages={this.getMessages()}/>
</div>
<div className="row-1 row-sm-1 row-md-1 row-lg-1 row-xl-1">
<ChatChannelInput onSendClicked={(input: string) => this.sendMessage(input)}/>
</div>
</div>
</div>
);
}
}
export default Chat我没有错误,一切运行顺利,但是更新不会刷新屏幕,我也不明白为什么。
messageStore
import { observable, computed, action } from 'mobx';
import { MessageModel } from 'app/models';
export class MessagesStore {
constructor(items: Array<MessageModel>) {
this.Messages = items;
}
@observable public Messages: Array<MessageModel>;
@computed
get getMessages() {
return this.Messages;
}
@action
addMessage = (item: MessageModel): void => {
this.Messages.push(item);
};
@action
setMessages = (items: Array<MessageModel>): void => {
this.Messages = items
};
@action
deleteMessage = (id: string): void => {
this.Messages = this.Messages.filter((Message) => Message.id !== id);
};
}
export default MessagesStore;我想我已经把所有的东西都放好了,尽管问更多的细节,谢谢你的帮助!
免责声明:首次使用MobX
发布于 2019-09-13 17:42:52
有两个问题:
在您的MessagesStore中,您没有正确地使用@可观的。@使您的字段的初始值可以观察到。但是在MessageStore的构造函数中,您将立即用一个常规的、不可观测的数组来替换这个值。因此,MessageStore.Messages永远不会被观察到,也不会触发观察者组件的任何重呈现。
您应该做的是使用一个数组初始化MessageStore.Messages字段,该数组将是可观察的,并且永远不要将不可观测的数组分配给该字段。如果您需要用另一个数组替换这个数组,正如您在MessageStore的构造函数和MessageStore.deleteMessage中所做的那样,您应该使用MobX的可观察数组的.replace方法,它将用另一个数组的内容替换可观察数组的内容。
export class MessagesStore {
constructor(items: Array<MessageModel>) {
this.Messages.replace(items);
}
@observable public Messages = new Array<MessageModel>();
...
@action
deleteMessage = (id: string): void => {
this.Messages.replace(this.Messages.filter((Message) => Message.id !== id));
};
}这样,MessageStore.Messages将是可观察的,并且您的组件观察到它的变化将按照预期重新呈现。
第二个问题是您的Chat组件没有观察到MessageStore.Messages的更改,所以说更改永远不会触发Chat的重新呈现。原因如下(来自MobX的文件):
MobX可以做很多事情,但是它不能使原始值可以被观察到(尽管它可以将它们封装在一个对象中--参见装箱的可观测值)。所以不是可以观察到的值,而是对象的属性。这意味着@观察者实际上对取消引用一个值这一事实做出了反应。
<ChatChannelMessagesList messages={this.getMessages()}/>在这里,您只将MessageStore.Messages作为一个值传递给ChatChannelMessagesList。您没有取消引用它(这意味着访问它的任何属性,例如迭代数组),因此Chat即使标记为@观察者,也不会对MessageStore.Messages的内容更改做出反应。
对这些更改作出反应的组件是第一个实际访问数组内容的组件,可能是ChatChannelMessagesList。我的猜测是,这个组件没有被标记为@观察者,并且从不对消息更新做出反应,这就是为什么您没有看到任何重新呈现的原因。
对于这个问题,您有两种解决方案:- dereference (访问Chat中的内容),所以当有新消息时,它会重新呈现--让ChatChannelMessagesList (或者第一个组件取消引用MessageStore.Messages) @ChatChannelMessagesList,这样它就会对更改做出反应。
第二种解决方案更好,因为您应该总是尽可能晚地取消对可观测值的引用,以避免对不依赖于这些更改的父组件进行无用的重新呈现。在您的示例中,当Chat的内容发生更改时,重新呈现MessageStore.Messages将毫无用处,因为Chat无论如何都会呈现相同的内容。
概述:
https://stackoverflow.com/questions/57926899
复制相似问题