【问题标题】:× TypeError: Cannot read properties of undefined (reading 'getState')× TypeError: Cannot read properties of undefined (reading 'getState')
【发布时间】:2021-11-08 09:43:54
【问题描述】:

我是初学者,正在学习 react 和 redux。我写了这个关于如何在 redux 中使用 connect.js 的演示。搜索此类问题,但我的代码没有正确答案。我有一个未定义的上下文。是错字吗?还是我以错误的方式传递了上下文?提前致谢。这是我的代码。

index.js

import React from "react";
import ReactDOM from "react-dom";
import store from "./store";

import { Provider } from "react-redux";
import App from "./App";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

/store/index.js

import { createStore } from "redux";
import reducer from "./reducer.js";
const store = createStore(reducer);
export default store;

/store/reducer.js

import { ADD, SUB, MUL, DIV } from './constants.js'

// or initialState
const defaultState = {
  counter: 0
}

function reducer(state = defaultState, action) {
  switch (action.type) {
    case ADD:
      return {...state, counter: state.counter + action.num};
    case SUB:
      return {...state, counter: state.counter - action.num};
    case MUL:
      return {...state, counter: state.counter * action.num};
    case DIV:
      return {...state, counter: state.counter / action.num};
    default:
      return state;
  }
}

export default reducer

connect.js

import React, { PureComponent } from "react";
import { StoreContext } from "./context";

export default function connect(mapStateToProps, mapDispatchToProps) {
  return function enhanceHOC(WrappedCpn) {
    class EnhanceCpn extends PureComponent {
      constructor(props, context) {
        super(props, context);
        console.log('connect props', props);
        console.log('connect context', context);  // context is undefined here
        this.state = {
          storeState: mapStateToProps(context.getState()),
        };
      }

      componentDidMount() {
        this.unSubscribe = this.context.subscribe(() => {
          this.setState({
            counter: mapStateToProps(this.context.getState()),
          });
        });
      }

      componentWillUnmount() {
        this.unSubscribe();
      }

      render() {
        return (
          <WrappedCpn
            {...this.props}
            {...mapStateToProps(this.context.getState())}
            {...mapDispatchToProps(this.context.dispatch)}
          />
        );
      }
    }
    EnhanceCpn.contextType = StoreContext;
    return EnhanceCpn;
  };
}

context.js

import React from "react";
const StoreContext = React.createContext();
export {
  StoreContext
}

App.js

import React, { PureComponent } from 'react'
import My from './pages/my'

export default class App extends PureComponent {
  constructor(props, context) {
    super(props, context);

    console.log('APP props', props);
    console.log('APP context', context); // context got value
  }

  render() {
    return (
      <div>
        <My />
      </div>
    )
  }
}

我的.js

import React, { PureComponent } from 'react'
import { sub, mul } from '../store/actionCreators'
import connect from '../utils/connect'

class My extends PureComponent {

  render() {
    return (
      <div>
      <h3>my</h3>
      <h3>counter: { this.props.counter }</h3>
      <button onClick={e => this.props.subNum()}>-2</button>
      <button onClick={e => this.props.mulNUm(5)}>*5</button>
    </div>
    )
  }
}

const mapStateToProps = state => ({
  counter: state.counter
})

const mapDispatchToProps = dispatch => ({
  subNum: (num = -2) => {
    dispatch(sub(num))
  },
  mulNUm: num => {
    dispatch(mul(num))
  }

})

export default connect(mapStateToProps, mapDispatchToProps)(My)

actionCreators.js

import { ADD, SUB, MUL, DIV } from './constants.js'

export function add(num) {
  return {
    type: ADD,
    num
  }
}

export const sub = (num) => {
  return {
    type: SUB,
    num
  }
}

export const mul = (num) => ({
  type: MUL,
  num
})

export const div = num => ({
  type: DIV,
  num
})

constants.js

const ADD = 'ADD_ACTION'
const SUB = 'SUB_ACTION'
const MUL = 'MUL_ACTION'
const DIV = 'DIV_ACTION'

export { ADD, SUB, MUL, DIV }

【问题讨论】:

  • 你的actionCreators在哪里?
  • 您是否想创建自己的connect HOC 来娱乐或其他什么?为什么不使用/利用react-redux?如果我没记错的话,React 不推荐使用 constructor(props, context) 签名。
  • 我编辑我的问题并发布 actionCreators.js。是的,我正在尝试创建自己的连接 hoc。 App.js 中的构造函数(道具,上下文)正在工作
  • 如果你正在学习redux,不妨学习modern style写reducers

标签: javascript reactjs redux react-redux jsx


【解决方案1】:

来自docs,这是关于Class.contextType 的内容:

可以为类的contextType 属性分配一个上下文对象 由React.createContext() 创建。使用此属性可以让您 使用该上下文类型的最接近的当前值 this.context。您可以在任何生命周期方法中引用它 包括渲染功能。

在您的情况下,您似乎只是缺少使用 context 道具将自定义 StoreContext 传递给 redux Provider

您需要执行以下操作:

import React from "react";
import ReactDOM from "react-dom";
import store from "./store";
import { StoreContext } from "./context";

import { Provider } from "react-redux";
import App from "./App";

ReactDOM.render(
  <Provider store={store} context={StoreContext}>
    <App />
  </Provider>,
  document.getElementById("root")
);

另见https://react-redux.js.org/using-react-redux/accessing-store#providing-custom-context

【讨论】:

  • 感谢您的回答。 适合我
【解决方案2】:

我遇到了同样的问题,并通过在与应用 Provider 的根组件相同的文件上创建存储来解决。示例代码如下:

 <Provider store={createStore(reducers)}>
    <App />
 </Provider>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-10
    • 2021-11-03
    • 2021-12-31
    • 1970-01-01
    • 2022-07-09
    • 2022-01-11
    • 2021-12-11
    • 1970-01-01
    相关资源
    最近更新 更多