Redux 状态未在 reducer 中按预期构建

Posted

技术标签:

【中文标题】Redux 状态未在 reducer 中按预期构建【英文标题】:Redux state not getting built as expected in reducers 【发布时间】:2019-05-24 10:27:03 【问题描述】:

我正在使用 React 和 Redux 构建一个简单的联系人应用程序。我的状态对象如下所示:


  "contacts": [
    
      "name": "Miguel Camilo",
      "phone": "123456789"
    ,
    
      "name": "Peter",
      "phone": "883292300348"
    ,
    
      "name": "Jessica",
      "phone": "8743847638473"
    ,
    
      "name": "Michael",
      "phone": "0988765553"
    
  ],
  "activeContact": 
    "name": "Peter",
    "phone": "883292300348"
  

我正在尝试构建一个添加联系人功能,该功能将从页面上的输入中获取姓名和号码,并将它们添加到该州的 contacts 数组中。它是这样构建的:

ContactsList 组件:

class ContactList extends Component 
  renderList() 
    return this.props.contacts.map((contact) => 
      return (
        <li
          key=contact.phone
          onClick=() => this.props.selectContact(contact)
          className='list-group-item'>contact.name</li>
      );
    );
  
  render() 
    return (
      <ul className = 'list-group col-sm-4'>
        this.renderList()
      </ul>
    );
  


function mapStateToProps(state) 
  return 
    contacts: state.contacts
  ;


function mapDispatchToProps(dispatch) 
  return bindActionCreators( selectContact: selectContact , dispatch);


export default connect(mapStateToProps, mapDispatchToProps)(ContactList)

添加联系人组件:

class AddContactModal extends Component 

  constructor() 
    super();
    this.state = firstName: "", phone: "";
  

  handleNameChange(event) 
    this.setState(firstName: event.target.value)
  

  handlePhoneChange(event) 
    this.setState(phone: event.target.value);
  

  render() 

    return(
      <div>
        <input type="text" className="name" placeholder="Contact Name" onChange=(event) => this.handleNameChange(event)/>
        <input type="text" className="phone" placeholder="Contact Phone" onChange=(event) => this.handlePhoneChange(event)/>
        <AddContactButton firstName=this.state.firstName firstName=this.state.phone onClick=() => this.props.addContact("name": this.state.firstName, "phone": this.state.phone)/>
      </div>
    );
  


function mapStateToProps(state) 
  console.log('mapstatetoprops:');
  console.log(state);
  return 
    contacts: state.contacts
  ;


function mapDispatchToProps(dispatch) 
  return bindActionCreators( addContact: addContact , dispatch);


export default connect(mapStateToProps, mapDispatchToProps)(AddContactModal)

Contacts Reducer(包含 ADD_CONTACT 处理程序):

export default function (state =  contacts : [] , action) 

  switch (action.type) 
    case 'ADD_CONTACT':
      console.log(state);
      return Object.assign(, state, 
        contacts: state.concat([
          
            name: action.payload.name,
            phone: action.payload.phone
          
        ])
      )
    default:
      return state;
  

应用的 index.js 建立商店的地方:

const createStoreWithMiddleware = applyMiddleware()(createStore);
const initialState = 
  "contacts": [
    
      "name": "Miguel Camilo",
      "phone": "123456789"
    ,
    
      "name": "Peter",
      "phone": "883292300348"
    ,
    
      "name": "Jessica",
      "phone": "8743847638473"
    ,
    
      "name": "Michael",
      "phone": "0988765553"
    
  ],
  "activeContact": null
;

ReactDOM.render(
  <Provider store= createStoreWithMiddleware(reducers, initialState) >
   <App />
  </Provider>
, document.querySelector('.container'));

并结合我的减速器:

const rootReducer = combineReducers(
  contacts: ContactsReducer,
  activeContact: ActiveContactReducer
);

export default rootReducer;

我的问题是,当我单击“添加联系人”按钮时,一个新的 contacts 数组被添加到该状态的现有 contacts 数组中,然后出于某种奇怪的原因,我的初始联系人列表被添加到国家。因此,当我登录this.props.contacts 时,单击添加联系人按钮后(在出错之前),它看起来如下所示:


  "0": 
    "name": "Miguel Camilo",
    "phone": "123456789"
  ,
  "1": 
    "name": "Peter",
    "phone": "883292300348"
  ,
  "2": 
    "name": "Jessica",
    "phone": "8743847638473"
  ,
  "3": 
    "name": "Michael",
    "phone": "0988765553"
  ,
  "contacts": [
    
      "name": "Miguel Camilo",
      "phone": "123456789"
    ,
    
      "name": "Peter",
      "phone": "883292300348"
    ,
    
      "name": "Jessica",
      "phone": "8743847638473"
    ,
    
      "name": "Michael",
      "phone": "0988765553"
    ,
    
      "name": "123",
      "phone": "123"
    
  ]

因此,在包含原始值和新值的原始 contacts 数组中添加了一个新的 contacts 数组。而原来的contacts数组保持不变。

我不确定这是为什么。最初我认为传递给我的 reducer 的 state 对象是完整状态,但它似乎只是我状态的 contacts 部分,所以我修改了我的 Object.assign() 调用以通过更改它来解决这个问题从 contacts: state.contacts.concat()contacts: state.concat() 但这仍然没有解决问题。

我希望返回到我的 ContactsList 组件的状态如下所示:


  "contacts": [
    
      "name": "Miguel Camilo",
      "phone": "123456789"
    ,
    
      "name": "Peter",
      "phone": "883292300348"
    ,
    
      "name": "Jessica",
      "phone": "8743847638473"
    ,
    
      "name": "Michael",
      "phone": "0988765553"
    ,
    
      "name": "this is the new contact",
      "phone": "123"
    
  ],
  "activeContact": 
    "name": "Peter",
    "phone": "883292300348"
  

只是在我的contacts 数组中添加了一个额外联系人的原始状态。任何想法我的实施有什么问题?任何帮助表示赞赏!

【问题讨论】:

你是否使用 combineReducers,如果使用也请添加该部分 @ShubhamKhatri 添加了 【参考方案1】:

问题在于如何分配初始状态。由于您使用 combineReducers 的一个键是联系人,因此您的 contactsReducers 得到

[
    
      "name": "Miguel Camilo",
      "phone": "123456789"
    ,
    
      "name": "Peter",
      "phone": "883292300348"
    ,
    
      "name": "Jessica",
      "phone": "8743847638473"
    ,
    
      "name": "Michael",
      "phone": "0988765553"
    
  ],

如你所愿


  contacts: [
    
      "name": "Miguel Camilo",
      "phone": "123456789"
    ,
    
      "name": "Peter",
      "phone": "883292300348"
    ,
    
      "name": "Jessica",
      "phone": "8743847638473"
    ,
    
      "name": "Michael",
      "phone": "0988765553"
    
  ]

所以你需要做的改变是

export default function (state = [], action) 

  switch (action.type) 
    case 'ADD_CONTACT':
      console.log(state);
      return state.concat([
          
            name: action.payload.name,
            phone: action.payload.phone
          
      ])
    default:
      return state;
  

进行上述更改后,一切都会奏效

【讨论】:

这确实有效!太感谢了。虽然状态不应该是不可变的,reducer 不应该只返回一个副本吗? state.concat 是否返回一个新对象而不是一个变异的 state concat 返回一个新数组并且不会改变原来的数组【参考方案2】:

你应该像这样改变你的状态

export default function (state =  contacts : [] , action) 

  switch (action.type) 
    case 'ADD_CONTACT':
      console.log(state);
      return 
       ...state,
       contacts: [...state.contacts, ...contacts]
      
    default:
      return state;
  

【讨论】:

以上是关于Redux 状态未在 reducer 中按预期构建的主要内容,如果未能解决你的问题,请参考以下文章

Redux 状态未在开发工具中更新,但当前状态正在反映在道具中

Redux 状态未在 Redux DevTool 中更新

Redux:Reducer 需要其他 Reducer 的状态?

Redux:重用reducer来更新多个状态属性

react+redux状态管理实现排序 合并多个reducer文件

Redux 动作/reducers 与直接设置状态