ReactJS Flux:检测组件之间的存储数据变化(不是父子关系)

ReactJS Flux: detect store data change between components (not parent and child relationship)

我有两个组件;菜单和信息。我需要在两个组件之间共享数据。我正在使用 Facebook Flux 模式。商店 class 通过 EventEmitter 进行了更改检测。检测父子关系。

蓝色的是菜单。红色是信息组件。我的网站之前没有使用 ReactJS。我正在尝试将 ReactJS 用于网站的一部分。我想对整个应用程序使用 ReactJS 是一种可能的解决方案,react-route..?,但我现在不能这样做。

有人知道吗?

==================================

编辑 1

我将我的整个代码发布到这个要点。

https://gist.github.com/y-zono/e1abf9e85a4707d81286b49f6a7f0117

我的目标是菜单和信息计数器显示相同的值。现在只增加了菜单计数器。

============================================= ===

Edit2 已解决

var React = require('react');
var ReactDOM = require('react-dom');
var Menu = require('./components/Menu.react');
var Info = require('./components/Info.react');
var CommonStore = require('./stores/CommonStore');

function renderMenu() {
    var state = CommonStore.getState();
    ReactDOM.render(
        <Menu data={state} />,
        document.getElementById('menu')
    );
}

CommonStore.addChangeListener(renderMenu);
renderMenu();

function renderInfo() {
    var state = CommonStore.getState();
    ReactDOM.render(
        <Info data={state} />,
        document.getElementById('info')
    );
}

CommonStore.addChangeListener(renderInfo);
renderInfo();

我认为主要问题是您没有使用商店来设置组件中的状态。

Info.react.js 应该是:

var React = require('react');
var CommonStore = require('../stores/CommonStore');
var CommonActionCreators = require('../actions/CommonActionCreators');

var Info = React.createClass({
    componentDidMount: function() {
        CommonStore.addChangeListener(this._handleChangeStore);
    },
    componentWillUnmount: function() {
        CommonStore.remChangeListener(this._handleChangeStore);
    },
    getInitialState() {
        return {
            clickFlag: CommonStore.getClickFlag()
        };
    },
    _handleChangeStore: function() {
        this.setState(clickFlag: CommonStore.getClickFlag();
        if (this.state.clickFlag) {
            console.log("menu is clicked"); // I want to detect the change.
        }
    },
});

此外,您还需要一个重置 clickFlag 的条件。

更新:

查看您的代码,您不应该让每个组件都使用自己单独的 <script>。相反,您应该有一个中央 js(通常称为 app.js),然后显示菜单和信息组件。然后您不需要将菜单分成 js/menu.js 和 js/components/Menu.react.js。同样,您不应该将信息组件分成 js/info.js 和 js/components/Menu.react.js。你应该只有 js/components/Menu.react.js 和 js/components/Info.react.js,app.js 处理你当前拥有的 js/menu.js 和 js/info.js 做.

示例:

index.html

<div>
  <div id="app"></div>
</div>

<script src="js/app.js"></script>

app.js

var React = require('react');
var ReactDOM = require('react-dom');
var Menu = require('./components/Menu.react');
var Info = require('./components/Info.react');

function renderDOM() {
    ReactDOM.render(
        <App />,
        document.getElementById('app')
    );
}

renderDOM();

Info.react.js

var Info = React.createClass({
    componentDidMount: function() {
        CommonStore.addChangeListener(this._handleChangeStore);
    },
    componentWillUnmount: function() {
        CommonStore.remChangeListener(this._handleChangeStore);
    },
    getInitialState() {
        return {
            count: CommonStore.getState()
        };
    },
    _handleChangeStore: function() {
        this.setState(count: CommonStore.getState();
    },
    render: function() {
        return (
            <div>
                info: {this.state.count}
            </div>
        );
    },
});

与其在组件级别订阅商店,为什么不在呈现组件的位置订阅(例如 menu.js)?

您可以将渲染代码包装在一个函数中,并在该函数中读取商店的状态,然后再将其作为道具传递给您的组件。您可以手动调用 render() 来进行第一次渲染,但也可以订阅将渲染函数作为回调传递的商店:

// menu.js
var React = require('react');
var ReactDOM = require('react-dom');
var Menu = require('./components/Menu.react');
var CommonStore = require('../stores/CommonStore');

function render() {
  var state = CommonStore.getState();
  ReactDOM.render(
      <Menu data={state} />,
      document.getElementById('menu')
  );
}

CommonStore.addChangeListener(render);
render();

注意:我不确定你的商店有什么吸气剂,所以我只是写了一些示例代码。

您的组件代码将简单地为:

// ./components/Menu.react.js
var React = require('react');
var CommonActionCreators = require('../actions/CommonActionCreators');

var Menu = React.createClass({
    _handleClickMenu: function() {
        CommonActionCreators.setMenuClieckOn();
    }
});

然后对 Info 组件重复该过程。

此 fiddle 展示了此方法在实践中的一个示例(使用一些虚拟组件、存储和动作创建器),以证明该概念有效:https://jsfiddle.net/vgskht45/1/