微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

React&Redux:即使使用mapStateToProps,组件的状态也不会更新

如何解决React&Redux:即使使用mapStateToProps,组件的状态也不会更新

我在下面发布了一个答案,但是如果有人可以解释为什么这样做是必要的,那么您会得到赏金,我经历了一个redux教程,觉得我没有了解mapdispatchToProps,只有{{1 }}。如果您可以更深入地解释mapStatetoPropsmapStatetoProps到底在做什么以及它们之间有何不同,我将为您提供赏金。


Minimum Reproducible Example


我有一个看起来像mapmapToProps函数

mapdispatchToProps

在我的const mapStatetoProps = state => { return { firstName: state.firstName,middleName: state.middleName,lastName: state.lastName,} } const ReduxTabForm = connect(mapStatetoProps)(MyTab) 组件中,如果没有在这2个字段中输入任何内容,则该按钮应该处于不活动状态,但是该按钮是否被禁用的状态不会改变

MyTab

该警报语句在页面刷新时执行,但是在我输入数据之后不执行任何时间。我已经检查了redux状态是否正在更新。但是该按钮不会更新,并且isdisabled函数不会运行多次

解决方法

我不知道这是否可以解决您的问题,但是也许这是下面的事情之一: 1-正如穆罕默德·费萨尔(Mohammad Faisal)所说,正确的呼叫道具形式应该是

const { firstName,lastName } = props;

2-代替reduxTabForm,也许您可​​以使用它:

export default connect(mapStateToProps)(MyTab);

3-最后,也许是“ isDisabled”中的错误:

for(let i = 0; i < requiredFields.length; i=i+1){
  if (!requiredFields){
    return false
  }
}

如果仔细看,您会发现您没有检查requeiredFields内部是否有错误,您正在寻找是否不存在错误if (!requiredFields),可能将条件更改为if(!requiredFields[i])以便进行检查每个变量,如果数组不存在则不是。

编辑:返回条件是否正确?不存在时返回False?

,
const ReduxTabForm = connect(mapStateToProps,null)(MyTab)

请尝试使用此代码段,因为您没有将调度功能传递给组件。最好传递空值。 mapdispatchtoProps与mapStateToProps的基本原理相同。您将函数存储在商店中(通常存储在动作中),并且在渲染组件时将这些函数附加到道具中。渲染组件后,您将能够运行商店中的功能。

,

我查看了您的reducer代码,它看起来像这样:

...
const reducer = combineReducers({
  formData: formReducer,})

export default reducer

这意味着您的redux状态结构如下:

state = {
  formData: {
    firstName: <value>,middleName: <value>,lastName: <value>,}
}

解决方案

因此,要使组件在redux状态更改时重新呈现,需要在mapStateToProps函数中预订正确的状态变量。将其更改为此,将起作用:

const mapStateToProps = state => {
  return {
    firstName: state.formData.firstName,// Note that I added "formData"
    middleName: state.formData.middleName,lastName: state.formData.lastName
  }
}

旁注:

  1. 最好使用道具而不是直接访问redux存储。
  2. 对于调试,console.log优于alert。 React DevTools和Redux DevTools甚至更好。
,

您的状态值将作为prop传递到您的组件。因此,如果要在组件内部访问它们,则应执行以下操作

 const {firstName,lastName} = props
,

您可以做的事情是这样的:

{{1}}

这样,如果您的任何字段都是虚假的,则按钮将被禁用。 (空字符串是虚假的)

,

React redux documentation also explains mapDispatchToProps

如果您从setFormData调用名为redux/actions.js的动作,则将把动作setFormData(是一个对象)映射到组件。操作setFromData代替mapDispatchToProps。这就是文档中关于将操作映射到您的组件的内容

如果该对象充满了动作创建者,则每个动作创建者将 变成了一个prop函数,该函数自动调度其动作


要解决您的问题,请将您的connect函数调用更改为此。

const ReduxApp = connect(
  setFormData,mapStateToProps
)(App)
,

您的问题出在此代码isDisabled()

     const isDisabled = () => {
    const {firstName,lastName} = store.getState().form
    const requiredFields = [firstName,lastName]
    alert(requiredFields)
    for(let i = 0; i < requiredFields.length; i=i+1){
      if (!requiredFields){
        return false
      }
    }
    return true
  }

您正在尝试在循环!requiredFields中进行测试,该循环是您创建的一个数组,即使该数组没有值,该数组也始终返回false。这是参考类型。您现在可以做的是

const isDisabled = () => {
    const {firstName,lastName]
    alert(requiredFields)
    for(let i = 0; i < requiredFields.length; i=i+1){
      if (!requiredFields[i]){
        return false
      }
    }
    return true
  }

您的循环将检查firstNAmeLastName的值是否未定义,测试应对此进行响应。

,

问题出在mapStateToProps方法中。您的代码将firstNAmelastName设置为formData 在状态对象之内,并且您正尝试直接从状态对象访问它。

codesandbox的项目已使用修复程序进行了更新。我没有在您的代码中修复任何其他问题,因此一切都只有mapStateToProps应该是:

const mapStateToProps = (state) => {
  return {
    firstName: state.formData["firstName"],middleName: state.middleName,lastName: state.formData["lastName"]
  };
};

,这将解决您的问题。 mapStateToProps是一种投影功能,可以将整个商店投影到某个对象,该对象仅具有基于组件要求的属性。

,

Redux仅在存储状态更改时才重新渲染组件。检查您是否仅更新商店的state属性而不是整个状态,因为redux通过比较它们的引用来比较状态,因此,如果您在reducer内执行以下操作:

State.firstName = action.payload.firstName;

return State;

然后将其更改为:

return {...State,firstName: action.payload.firstName}

注意:如果您无法理解这些信息,请也提供您的减速器代码,以便我了解您如何更新商店状态。

,
  1. 在GitHub上查看MRE,我想说的第一件事是您的按钮将只有一个状态,并且是刷新页面时isDisabled()方法返回的状态。这是因为每次您在输入字段上书写时,App组件都不会刷新,因此您将永远无法对其进行更改。

  2. 您需要在mapStateToProps函数中订阅正确的状态变量。像这样:

const mapStateToProps = state => {
    return {
        firstName: state.formData.firstName,middleName: state.formData.middleName,lastName: state.formData.lastName
    }
}
  1. 因此,既然您拥有此权利,就必须将这些道具引入到组件中,如下所示:
     function  App({firstName,lastName}) { ...
  1. 要补充的另一件事是,当您在reducer.js中创建化简器时,您没有初始化状态。如果不这样做,则firstNamelastName的初始状态将为空。这是您应该如何做:
import {combineReducers} from 'redux'
import {SET_FORM_DATA} from './actions'

const initialState = {
  firstName: "",lastName: ""
}

const formReducer = (state = initialState,action) => {
  if (action.type === SET_FORM_DATA){
    return {
      ...state,...action.payload
    }
  }else{
    return state
  }
}

const reducer = combineReducers({
  formData: formReducer,})

export default reducer
  1. 最后,您必须更新App:
function  App({firstName,lastName}) {
  return (
      <div className="App">
        <div className='bg-light rounded'>
          <div className='px-sm-5 pt-0 px-4 flexCenterCol mx-5'>

            <div>
            <input 
              type='text'
              className="form-control"
              placeholder="First Name"
              onChange={(e) => {
                store.dispatch(setFormData({'firstName': e.target.value}));
                console.log(firstName === "h");
              }}
            ></input>
            <input 
              type='text'
              className="form-control"
              placeholder="Last Name"
              onChange={(e) => {
                store.dispatch(setFormData({'lastName': e.target.value}))
                alert(JSON.stringify(store.getState()))

              }}
            ></input>

            </div>
            <button
              type="submit"
              disabled={firstName == "" || lastName == ""}
            >
              Button
            </button>
          </div>
        </div>
      </div>
  );
}

因此,通过这种方式,您将能够更新商店中的状态,并具有您正在寻找的动态行为。

,

isDisabled函数中,您从form读取数据:const {firstName,lastName} = store.getState().form,但我想它们已保存到formData

const {firstName,lastName} = store.getState().form更改为const {firstName,lastName} = store.getState().formData应该会有所帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。