0

我在下面发布了一个答案,但如果有人能解释为什么这是必要的,你会得到赏金,我经历了一个 redux 教程,感觉我没有了解mapDispatchToProps, 只有mapStateToProps. 如果你能在更深层次上解释究竟是什么mapStateToPropsmapDispatchToProps正在做什么以及它们有何不同,我会给你赏金。


最小可重现示例


我有一个看起来像的 mapStateToProps 函数

const mapStateToProps = state => {
  return {
    firstName: state.firstName,
    middleName: state.middleName,
    lastName: state.lastName,
  }
}

const ReduxTabForm = connect(mapStateToProps)(MyTab)

在我的MyTab组件中,我有一个按钮,如果这两个字段没有输入任何内容,则该按钮应该是非活动的,但是按钮是否被禁用的状态不会改变

function App() {
  const {firstName, lastName} = store.getState().formData

  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 true
      }
    }
    return false
  }

  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"
                    value={store.getState().formData['firstName']}
                    placeholder="First Name"
                    onChange={(e) => {
                        store.dispatch(setFormData({'firstName': e.target.value}))
                    }}
               ></input>
               <input 
                    type='text'
                    className="form-control"
                    value={store.getState().formData['lastName']}
                    placeholder="Last Name"
                    onChange={(e) => {
                        store.dispatch(setFormData({'lastName': e.target.value}))
                    }}
               ></input>

            </div>
            <button
                type="submit"
                disabled={isDisabled()}
            >
                Button
            </button>
        </div>
    </div>
  </div>
 )
}

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

4

11 回答 11

1

我不知道这是否会解决您的问题,但可能是以下情况之一: 1 - 正如 Mohammad Faisal 所说,调用 props 的正确形式应该是

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?

于 2020-09-25T18:36:52.693 回答
1
const ReduxTabForm = connect(mapStateToProps,null)(MyTab)

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

于 2020-09-29T10:04:20.023 回答
1

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

...
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. 使用 props 比直接访问 redux store 更好。
  2. 对于调试,console.log优先于alert. React DevTools 和 Redux DevTools 更好。
于 2020-10-03T04:03:30.373 回答
0

您的状态值作为道具传递给您的组件。所以如果你想在组件内部访问它们,你应该做这样的事情

 const {firstName, lastName} = props
于 2020-09-25T18:00:55.423 回答
0

你可以做的是这样的:

<button 
      type="submit"
      disabled={!fistname && !lastname}
    />

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

于 2020-09-25T18:47:40.400 回答
0

React redux 文档还解释了mapDispatchToProps

如果你调用你的动作setFormDataredux/actions.js那么你将把动作setFormData(它是一个对象)映射到你的组件。动作setFromData替换mapDispatchToProps。这就是文档中关于将操作映射到组件的内容

如果它是一个充满动作创建者的对象,每个动作创建者都会变成一个 prop 函数,在调用时会自动调度其动作。


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

const ReduxApp = connect(
  setFormData,
  mapStateToProps
)(App)
于 2020-09-28T15:53:09.633 回答
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
  }

您正在尝试在 loop 中进行测试!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值是否未定义,并且测试应该对此做出响应。

于 2020-09-29T18:27:49.017 回答
0

问题出在mapStateToProps方法上。您的代码正在设置firstNAme并且lastNameformData 状态对象中,您正试图直接从状态对象访问它。

代码框已使用修复程序更新了您的项目。我没有在您的代码中修复任何其他内容,所以一切都mapStateToProps应该是:

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

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

于 2020-09-30T23:21:37.403 回答
0

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

State.firstName = action.payload.firstName;

return State;

然后将其更改为:

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

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

于 2020-10-04T17:01:09.193 回答
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. 最后你必须更新应用程序:
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>
  );
}

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

于 2020-10-04T17:24:12.880 回答
0

在函数中,您从:isDisabled读取数据,但我猜它们已保存到.formconst {firstName, lastName} = store.getState().formformData

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

于 2020-10-04T20:47:33.077 回答