【问题标题】:Connected component reads from Redux store, but action creators don't update it连接的组件从 Redux 存储读取,但操作创建者不更新它
【发布时间】:2020-10-30 21:09:21
【问题描述】:

我有一个连接的组件,它从 Redux 存储中获取信息并将其显示在屏幕上。但是每当我尝试发送一个动作来更新状态时,它最终都不会做任何事情:

AppSettings.js

import {
  MINUTE_MS,
  MINUTE_S,
} from '../constants'
import {
  decrementSession,
  incrementSession,
} from './timerSlice'

import React from 'react'
import { connect } from 'react-redux'
import equal from 'fast-deep-equal'

/* eslint-disable no-useless-constructor */

export class AppSettings extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      sessionLength: this.props.sessionLength,
    }
  }

  componentDidUpdate(prevProps) {
    if (!equal(this.props, prevProps)) {
      this.setState((_, props) => {
        return {
          sessionLength: props.sessionLength,
        };
      })
    }
  }

  render() {
    let sessionLength = Math.floor(this.props.sessionLength / MINUTE_MS) % MINUTE_S
    sessionLength = ('0' + sessionLength).slice(-2)
    
    return (
      <div>
        <div>
          <h3>
            session
          </h3>
          <button 
            id='sessionUp'
            onClick={this.props.incrementSession}
            >
            up
          </button>
          <h4>
            {sessionLength}
          </h4>
          <button 
            id='sessionDown'
            onClick={this.props.decrementSession}
            >
            down
          </button>
        </div>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    sessionLength: state['sessionLength'],
  };
}

function mapDispatchToProps() {
  return {
    decrementSession,
    incrementSession,
  };
}

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(AppSettings)

timerSlice.js

import {
  DEFAULT_SESSION,
  MINUTE_MS,
} from '../constants'

import { createSlice } from '@reduxjs/toolkit'

export const timerSlice = createSlice({
  name: 'timer',
  initialState: {
    sessionLength: DEFAULT_SESSION,
  },
  reducers: {
    decrementSession(state) {
      state['sessionLength'] -= MINUTE_MS
    },
    incrementSession(state) {
      state['sessionLength'] += MINUTE_MS
    },
  }
})

export const {
  decrementSession,
  incrementSession,
} = timerSlice.actions

export default timerSlice.reducer

store.js

import { configureStore } from '@reduxjs/toolkit'
import reducer from '../features/timerSlice'

const store = configureStore({
  reducer: reducer
})

export default store

在初始渲染时,组件从存储中读取就可以了,并显示适当的值。单元测试表明,组件在传递新道具时会更新呈现在屏幕上的值。我的单元测试还表明,只要按下按钮,就会调用适当的函数。我在浏览器中运行我的应用程序,它显示 Redux 商店根本没有更新。

为什么我的商店在我尝试从我的组件调度操作时没有响应?

【问题讨论】:

  • 你安装了 redux-devtools(浏览器扩展)吗?您能否验证您的商店至少注册了已发送的操作?它可以方便地让您直接从开发工具 BTW 调度操作。如果您看到记录的操作,请检查操作负载(如果有)和状态差异。
  • @DrewReese 原来商店没有注册该操作已被调度。当我使用 redux-devtools 手动调度 timer/incrementSession 类型的操作时,它会注册更改,但当我单击应用程序上的任何按钮时不会。在这种情况下你有什么建议?

标签: javascript reactjs redux react-redux redux-toolkit


【解决方案1】:

mapDispatchToProps 在当前设置中似乎有问题。我通过将其转换为函数组件并使用useDispatch 调用操作来使其工作。

本地状态是不必要的。直接使用从 redux 中选择的值即可。

export const AppSettings = () => {

  const dispatch = useDispatch();

  const sessionLength = useSelector(state => state.sessionLength);

  const seconds = Math.floor(sessionLength / MINUTE_MS) % MINUTE_S
  const secondsString = ('0' + seconds).slice(-2)
  
  return (
    <div>
      <div>
        <h3>
          session
        </h3>
        <button 
          id='sessionUp'
          onClick={() => dispatch(incrementSession())}
          >
          up
        </button>
        <h4>
          {secondsString}
        </h4>
        <button 
          id='sessionDown'
          onClick={() => dispatch(decrementSession())}
          >
          down
        </button>
      </div>
    </div>
  );
}

Code Sandbox Link

【讨论】:

  • 应该使用对象速记符号。我能想到的对象速记失败的唯一情况是,如果有循环导入,incrementSessiondecrementSession 在初始运行时为undefined,并且仅在以后可用。所以 maye 寻找循环导入可以帮助找到根本问题。
  • @phry 我认为循环导入也不是问题所在。当我刚刚停止使用mapDispatchToProps 并使用连接组件默认的this.props.dispatch() 方法时,它与incrementSessiondecrementSession 一起工作得很好。
  • @phry 我开始使用 mapDispatchToProps 与同一个文件中的所有内容一起玩。老实说,我不知道为什么它不起作用,因为它看起来对我来说是正确的。但我可以确认它不起作用。
  • @jaime 不会反对循环依赖。循环依赖的要点是循环导入的东西在代码的初始评估中可能是undefined(定义你的mapStateToProps对象时),但稍后可以引用,例如在您的组件的方法调用中。但是按照@LindaPaiste 所说的,可能不是这样。神秘!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-26
  • 2018-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-15
  • 2021-05-12
相关资源
最近更新 更多