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

时间:2020-09-25 17:53:25

标签: reactjs redux mapstatetoprops mapdispatchtoprops

我在下面发布了一个答案,但是如果有人可以解释为什么这样做是必要的,那么您会得到赏金,我经历了一个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函数不会运行多次

11 个答案:

答案 0 :(得分:1)

我不知道这是否可以解决您的问题,但是也许这是下面的事情之一: 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?

答案 1 :(得分:1)

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

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

答案 2 :(得分:1)

我查看了您的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甚至更好。

答案 3 :(得分:0)

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

 const {firstName, lastName} = props

答案 4 :(得分:0)

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

{{1}}

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

答案 5 :(得分:0)

React redux documentation also explains mapDispatchToProps

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

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


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

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

答案 6 :(得分:0)

您的问题出在此代码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} = store.getState().form
    const requiredFields = [firstName, lastName]
    alert(requiredFields)
    for(let i = 0; i < requiredFields.length; i=i+1){
      if (!requiredFields[i]){
        return false
      }
    }
    return true
  }

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

答案 7 :(得分:0)

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

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

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

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

答案 8 :(得分:0)

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

State.firstName = action.payload.firstName;

return State;

然后将其更改为:

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

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

答案 9 :(得分:0)

  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>
  );
}

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

答案 10 :(得分:0)

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

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