2016-02-27 21 views
139

说我有以下几点:在动作创建器中访问Redux状态?

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    } 
} 

而在这一行动的创建者,我要访问的全局存储状态(全减速)。它是更好地做到这一点:

import store from '../store'; 

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    items: store.getState().otherReducer.items, 
    } 
} 

或本:

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return (dispatch, getState) => { 
    const {items} = getState().otherReducer; 

    dispatch(anotherAction(items)); 
    } 
} 

回答

12

当你的场景很简单,你可以使用

import store from '../store'; 

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    items: store.getState().otherReducer.items, 
    } 
} 

但有时你action creator需要触发多行动

例如异步请求,所以你需要 REQUEST_LOADREQUEST_LOAD_SUCCESSREQUEST_LOAD_FAIL行动

export const [REQUEST_LOAD, REQUEST_LOAD_SUCCESS, REQUEST_LOAD_FAIL] = [`REQUEST_LOAD` 
    `REQUEST_LOAD_SUCCESS` 
    `REQUEST_LOAD_FAIL` 
] 
export function someAction() { 
    return (dispatch, getState) => { 
     const { 
      items 
     } = getState().otherReducer; 
     dispatch({ 
      type: REQUEST_LOAD, 
      loading: true 
     }); 
     $.ajax('url', { 
      success: (data) => { 
       dispatch({ 
        type: REQUEST_LOAD_SUCCESS, 
        loading: false, 
        data: data 
       }); 
      }, 
      error: (error) => { 
       dispatch({ 
        type: REQUEST_LOAD_FAIL, 
        loading: false, 
        error: error 
       }); 
      } 
     }) 
    } 
} 

注:你需要redux-thunk在行动的创建者返回功能

+1

我可以问一下,是否应该检查状态“加载”的状态,以便在第一个Ajax请求没有完成的时候进行另一个Ajax请求? – JoeTidee

239

上都安有行动的创作者访问状态是否是一个好主意,不同的意见。我认为可以接受的几个用例是在您发出请求之前检查缓存的数据,或者检查您是否经过身份验证(换句话说,执行条件分发)。我认为在动作创建器中传递数据(如state.something.items)绝对是一种反模式,因为它遮蔽了更改历史记录而不鼓励:如果有错误并且items不正确,很难跟踪,其中那些错误值来自于它们,因为它们已经是行动的一部分,而不是由减速器响应行动直接计算出来。所以要小心。 (进一步讨论动作创作者访问状态的利弊,请参阅博客文章Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction, and Reusability。)

如果您发现需要此操作,那么您建议的两种方法都可以。第一种方法不需要任何中间件:

import store from '../store'; 

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return { 
    type: SOME_ACTION, 
    items: store.getState().otherReducer.items, 
    } 
} 

但是你可以看到,它依赖于store是从一些模块导出一个单例。 我们不建议,因为它使得它更难add server rendering to your app因为在大多数情况下在服务器上,你会希望有每个请求一个独立的专卖店。因此,尽管技术上这种方法有效,但我们不建议从模块中导出商店。

这就是为什么我们推荐第二种方法:

export const SOME_ACTION = 'SOME_ACTION'; 
export function someAction() { 
    return (dispatch, getState) => { 
    const {items} = getState().otherReducer; 

    dispatch(anotherAction(items)); 
    } 
} 

这将需要您使用终极版咚中间件,但它工作正常客户端上和服务器上。你可以阅读更多关于终极版咚和为什么有必要在这种情况下here

理想情况下,你的行为不应该是“肥”,应包含的信息尽可能少的,但你应该感到自由地做什么工作最适合你自己的应用程序。 Redux FAQ有关于splitting logic between action creators and reducerstimes when it may be useful to use getState in an action creator的信息。

+4

我有一种情况时,选择组件中的某些内容可能会触发PUT或POST,具体取决于商店是否包含与组件相关的数据。将PUT/POST选择的业务逻辑放在组件中而不是基于thunk的动作创建器是否更好? – vicusbass

+2

这两个作品,所以取决于你。 –

+1

最佳做法是什么?我现在正面临类似的问题,我在我的动作创建者中使用getState。在我的情况下,我使用它来确定如果表单有未决更改(如果是的话,我将分派一个显示对话框的操作)。 –

1

我想指出,从商店中读取并不是那么糟糕 - 根据商店来决定应该做什么可能更方便,而不是将所有内容都传递给组件,然后作为功​​能的参数。我完全同意Dan的观点,除非你100%确定你只用于客户端渲染(否则很难追踪可能出现的错误),否则最好不要将商店用作单人游戏。

I have created a library最近要处理redux的冗长问题,我认为将所有内容放入中间件是一个好主意,因此您将everyhing作为依赖注入。

所以,你的例子看起来像:

import { createSyncTile } from 'redux-tiles'; 

const someTile = createSyncTile({ 
    type: ['some', 'tile'], 
    fn: ({ params, selectors, getState }) => { 
    return { 
     data: params.data, 
     items: selectors.another.tile(getState()) 
    }; 
    }, 
}); 

然而,正如你所看到的,我们并不真的在这里修改数据,所以是一个很好的机会,我们就可以使用这个选择其他地方将它结合到别的地方。