【问题标题】:ReactJS: Uncaught TypeError: Cannot read property 'subscribe' of undefined(…)ReactJS:未捕获的类型错误:无法读取未定义的属性“订阅”(…)
【发布时间】:2017-04-13 21:33:17
【问题描述】:

我正在尝试使用 React 和 Redux 构建一个计时器。

我尽可能地分离关注点。请帮我找到一个可行的解决方案!谢谢。

错误:未捕获的类型错误:无法读取未定义(…)的属性“订阅”

定时器组件

Timer.js

import React, { Component } from 'react';
import timer from '../reducers/index.js';
import store from '../stores/timerStore.js';


 // React Component to display the timer
 class Timer extends Component {
    constructor() {
     super();
     this.start = this.start.bind(this);
     this.stop = this.stop.bind(this);
    }

    start() {
      store.dispatch({
      type: 'START_TIMER',
      offset: Date.now(),
    });
   }
  stop() {
    store.dispatch({
    type: 'STOP_TIMER'
  });
 }
format(time) {
   const pad = (time, length) => {
     while (time.length < length) {
     time = '0' + time;
   }
  return time;
}

time = new Date(time);
let m = pad(time.getMinutes().toString(), 2);
let s = pad(time.getSeconds().toString(), 2);
let ms = pad(time.getMilliseconds().toString(), 3);

 return `${m} : ${s} . ${ms}`;
}

render() {
  return (
    <div>
      <h1>Time: {this.format(this.props.time)}</h1>
      <button onClick={this.props.isOn ? this.stop : this.start}>
       { this.props.isOn ? 'Stop' : 'Start' }
      </button>
    </div>
   );
  }
}



export default Timer;

定时器减速器

    timer.js

   // Initial state for reducer
   const initialState = {
      isOn: false,
      time: 0
    };


    function timer(state = initialState, action) {
       switch (action.type) {
          case 'START_TIMER':
            return {
             ...initialState,
             isOn: true,
             offset: action.offset,
             };

          case 'STOP_TIMER':
           return {
             isOn: false,
             time: state.time
            };

         case 'TICK':
           return {
            ...state,
            time: state.time + (action.time - state.offset),
            offset: action.time
          };

        default:
        return state;
      }
     }

   export default timer;

定时器存储

  timerStore.js

  import { createStore } from 'redux';
  import timer from '../reducers/index.js';

  // Create store using the reducer
  export const store = createStore(timer);

主应用组件

   index.js

   import React, { Component } from 'react';
   import ReactDOM from 'react-dom';
   import Timer from './components/Timer.js';
   import store from './stores/timerStore.js';

   const render = () => {
      ReactDOM.render(
      <Timer
          time={store.getState().time}
          isOn={store.getState().isOn}
          interval={store.getState().interval}
       />,
      document.getElementById("app")
     );
    }

    store.subscribe(render);

    var interval = null;
     store.subscribe(() => {
       if (store.getState().isOn && interval === null) {
          interval = setInterval(() => {
           store.dispatch({
        type: 'TICK',
        time: Date.now()
       });
     });
     }
   if (!store.getState().isOn && interval !== null) {
      clearInterval(interval);
      interval = null;
     }
    });

  render();

【问题讨论】:

  • 您是否得到了文件和行号以及错误信息?

标签: reactjs redux react-redux


【解决方案1】:

你有两个不同的问题:

首先,您正在执行存储变量的“命名导出”,但该文件的“默认导入”。您需要确保两者匹配。要么执行export default createStore(timer)import store from "./stores/timerStore",要么执行export const store = createStore(timer)import {store} from "./stores/timerStore"

其次,您真的不应该对商店进行“手动”订阅。 React-Redux 包提供了一个connect 函数,它会生成容器组件,为你管理订阅和更新过程。

另外观察一下,名为“stores”的文件夹表明您正在创建多个 Redux 存储。虽然您可以这样做,但这不是推荐的方法。

更新

而且,看看它,你遇到了第三个问题:&lt;Timer&gt; 组件不会重新渲染,因为它不知道商店已经更新。它只会使用来自ReactDOM.render(&lt;Timer&gt;) 调用的初始值。

根据我刚刚在下面写的评论,你真的应该把它写成几个不同的组件。一个组件应该连接到 Redux 存储并使用 setInterval 管理计时器逻辑,它应该呈现另一个显示计时器信息的组件。

【讨论】:

  • +1 看好第一点。对于管理计时器的订阅,直接使用 .subscribe 是有意义的,因为它不作为 DOM 组件的一部分存在。
  • 实际上,这对于几个“容器”组件来说似乎很有用。 connect 调用将生成一个访问 Redux 存储的容器,并且传递给 connect 的组件本身可能是一个“容器”类型的组件,用于管理间隔并呈现 &lt;Timer&gt;
  • 您的更新不正确。它将重新渲染。每次状态变化时都会调用渲染函数并获取状态项的当前值。
  • 是的,您可以拥有管理间隔的 React 组件。我觉得这种方式比较好,redux 的创建者也同意我的看法:github.com/reactjs/redux/issues/1194#issuecomment-233193780。此代码改编自我在 github 问题中发布的如何执行此操作的示例。
  • 啊,我的错,错过了store.subscribe(render)
猜你喜欢
  • 1970-01-01
  • 2016-08-09
  • 1970-01-01
  • 2018-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多