国家似乎被覆盖而不是合并

时间:2016-04-21 18:25:33

标签: reactjs react-redux

我目前正在尝试学习Redux,我认为我必须实现它错误,因为只有在页面上呈现的最后一个组件才能实现。我怀疑每次都会被覆盖。

我遵循了this教程,它只使用了一个数据检索示例,所以我可能只是误解了如何写入状态。

这是我的减速机。我出错的任何想法?这一切看起来都非常冗长,是否有一种DRYer写出来的方法呢?

import Immutable from 'seamless-immutable';
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';

// Import actions
import {
  REQUEST_CONFIG,
  GET_CONFIG,
  REQUEST_PAGES,
  GET_PAGES,
  REQUEST_SOCIAL_LINKS,
  GET_SOCIAL_LINKS,
  REQUEST_NAV,
  GET_NAV
} from './actions';

const configInitialState = Immutable({
  items: [],
  isFetching: false
})

const pagesInitialState = Immutable({
  items: [],
  isFetching: false
})

const socialLinksInitialState = Immutable({
  items: [],
  isFetching: false
})

const navInitialState = Immutable({
  items: [],
  isFetching: false
})

export function config(state = configInitialState, action) {
  switch (action.type) {
    case GET_CONFIG :
      return Immutable(state).merge({
        items: action.payload.config[0],
        isFetching: false
      })
    case REQUEST_CONFIG :
      return Immutable(state).merge({
        isFetching: true
      })
    default:
      return state;
  }
}

export function pages(state = pagesInitialState, action) {
  switch (action.type) {
    case GET_PAGES :
      return Immutable(state).merge({
        items: action.payload.pages,
        isFetching: false
      })
    case REQUEST_PAGES :
      return Immutable(state).merge({
        isFetching: true
      })
    default:
      return state;
  }
}

export function socialLinks(state = socialLinksInitialState, action)      {
  switch (action.type) {
    case GET_SOCIAL_LINKS :
      return Immutable(state).merge({
        items: action.payload.socialLinks,
        isFetching: false
      })
    case REQUEST_SOCIAL_LINKS :
      return Immutable(state).merge({
        isFetching: true
      })
    default:
      return state;
  }
}

export function nav(state = navInitialState, action) {
  switch (action.type) {
    case GET_NAV :
      return Immutable(state).merge({
        items: action.payload.nav,
        isFetching: false
      })
    case REQUEST_NAV :
      return Immutable(state).merge({
        isFetching: true
      })
    default:
      return state;
  }
}

const rootReducer = combineReducers({
  config,
  pages,
  socialLinks,
  nav,
  routing: routerReducer
});

export default rootReducer;

如果需要,以下是我的一个组件的示例:

import React from 'react';
import { Link } from 'react-router';
import { connect } from 'react-redux';
import { navLoad } from '../../../scripts/actions';

export default class HeaderNav extends React.Component {
  componentWillMount() {
    const { dispatch } = this.props;
    dispatch(navLoad());
  }

  render() {
    const { nav } = this.props;
    const navitems = nav && nav.items ? nav.items.asMutable().map((item) => {
      if(item.inNav === 'header' || item.inNav === 'both') {
        return <li key={item._id}><Link to={item.slug}>{item.name}</Link></li>
      }
    }) : null;
    if(nav.isFetching) {
      return(
        <section class="loader">
          <span>Content is loading...</span>
        </section>
      )
    } else {
      return(
        <nav class="c-primary-nav">
          <span class="c-primary-nav_toggle">Menu</span>
          <ul>
            { navitems }
          </ul>
        </nav>
      )
    }
  }
}

function select(state) {
  const { nav } = state;
  return {
    nav
  };
}

export default connect(select)(HeaderNav);

以下是调用组件的位置:

import React from 'react';
import HeaderNav from './Header/nav.jsx';
import SocialLinks from './Header/socialLinks.jsx';

export default class Header extends React.Component {
  render() {
    return(
      <header class="c-global-header" role="banner">
        <HeaderNav />
        <SocialLinks />
      </header>
    )
  }
}

更新:我仍然希望得到这个问题的答案,因为它仍然让我感到难过,我现在已经改变了一些代码,但无济于事。你可以在这里看到我的完整代码库:https://github.com/alexward1981/portfolio-react(所有相关内容都在'src'文件夹中)

5 个答案:

答案 0 :(得分:5)

我刚遇到同样的问题,问题出在reducer中,而不是默认switch case部分的return状态,我返回initialState。

export const getAppShopReducer = (state = initialState, action) => {
  switch (action.type) {
    case types.FETCH_APP_SHOP_SUCCESS:

      return state
        .set('loading', false)
        .set('user', action.payload.user)
        .set('appShop', action.payload.appShop)
        .set('shop', action.payload.shop)
        ;

    case types.FETCH_APP_SHOP_REQUEST:

      return initialState.set('loading', true);

    default:
      return state; // Here's the problem, it was `initialState`;
  }
};

答案 1 :(得分:0)

如果您的问题是您希望在页面更新时获取组件的新数据,那么componentWillMount()中的数据获取是不够的(因为它仅在第一次呈现组件时调用)

您还必须在另一个组件的生命周期方法componentWillReceiveProps()中添加数据获取:

componentWillReceiveProps(nextProps) {
  const { dispatch } = this.props;
  dispatch(navLoad());
}

您可以添加适当的条件(将nextProps与this.props进行比较),以检查是否确实需要在每次更新时获取新数据。

答案 2 :(得分:0)

我不熟悉无缝不可变,但您的问题可能与其在Reducer中的使用有关。你确定这个库真的会在状态发生变化时产生新的对象引用,因为redux需要它吗?

无论如何,您可能必须使用更多代码来正确组合redux和无缝不可变,例如this library

为简化起见,我认为您应该尝试使用普通的JS不变性模式(例如使用Object.assign()或对象扩展语法)而不是无缝不可变。例如,您可以像这样编写缩减器:

const navInitialState = {
  items: [],
  isFetching: false
}

function nav(state = navInitialState, action) {
  switch (action.type) {
    case GET_NAV :
      return {
        ...state,
        items: action.payload.nav,
        isFetching: false
      }
    case REQUEST_NAV :
      return {
        ...state,
        isFetching: true
      }
    default:
      return state
  }
}

答案 3 :(得分:0)

我能够通过阅读combineReducers

注释中的这个列表来解决我的问题

http://redux.js.org/docs/api/combineReducers.html#notes

如果undefined状态未正确处理,有些情况会自动失败。

答案 4 :(得分:-1)

在我从未发现过的所有内容之后,这是一个血腥的错字。谢谢你的帮助。