首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ReactJs,TypeScript,MobX -无法在存储数据更新上获得MobX刷新屏幕

ReactJs,TypeScript,MobX -无法在存储数据更新上获得MobX刷新屏幕
EN

Stack Overflow用户
提问于 2019-09-13 15:58:11
回答 1查看 581关注 0票数 0

我和mobx有个问题。事实上,我有一个简单的聊天室,它使用我自己定义的WebSocketService。虽然这个服务用我的API抽象交换,但是聊天本身处理消息的存储。

main.tsx (入口点)

代码语言:javascript
复制
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)

代码语言:javascript
复制
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

代码语言:javascript
复制
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

代码语言:javascript
复制
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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-09-13 17:42:52

有两个问题:

在您的MessagesStore中,您没有正确地使用@可观的@使您的字段的初始值可以观察到。但是在MessageStore的构造函数中,您将立即用一个常规的、不可观测的数组来替换这个值。因此,MessageStore.Messages永远不会被观察到,也不会触发观察者组件的任何重呈现。

您应该做的是使用一个数组初始化MessageStore.Messages字段,该数组将是可观察的,并且永远不要将不可观测的数组分配给该字段。如果您需要用另一个数组替换这个数组,正如您在MessageStore的构造函数和MessageStore.deleteMessage中所做的那样,您应该使用MobX的可观察数组的.replace方法,它将用另一个数组的内容替换可观察数组的内容。

代码语言:javascript
复制
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可以做很多事情,但是它不能使原始值可以被观察到(尽管它可以将它们封装在一个对象中--参见装箱的可观测值)。所以不是可以观察到的值,而是对象的属性。这意味着@观察者实际上对取消引用一个值这一事实做出了反应。

代码语言:javascript
复制
  <ChatChannelMessagesList messages={this.getMessages()}/>

在这里,您只将MessageStore.Messages作为一个值传递给ChatChannelMessagesList。您没有取消引用它(这意味着访问它的任何属性,例如迭代数组),因此Chat即使标记为@观察者,也不会对MessageStore.Messages的内容更改做出反应。

对这些更改作出反应的组件是第一个实际访问数组内容的组件,可能是ChatChannelMessagesList。我的猜测是,这个组件没有被标记为@观察者,并且从不对消息更新做出反应,这就是为什么您没有看到任何重新呈现的原因。

对于这个问题,您有两种解决方案:- dereference (访问Chat中的内容),所以当有新消息时,它会重新呈现--让ChatChannelMessagesList (或者第一个组件取消引用MessageStore.Messages) @ChatChannelMessagesList,这样它就会对更改做出反应。

第二种解决方案更好,因为您应该总是尽可能晚地取消对可观测值的引用,以避免对不依赖于这些更改的父组件进行无用的重新呈现。在您的示例中,当Chat的内容发生更改时,重新呈现MessageStore.Messages将毫无用处,因为Chat无论如何都会呈现相同的内容。

概述:

  • 不要用新数组重新分配包含可观察数组的字段,而是更改可观察数组的内容。
  • @观察者组件在访问可观察对象的属性时重新呈现,而不是它们的值。@观察者组件应该是那些访问这些属性的组件。
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57926899

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档