Javascript 如何访问 Redux reducer 内部的状态?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/39257740/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to access state inside Redux reducer?
提问by twilco
I have a reducer, and in order to calculate the new state I need data from the action and also data from a part of the state not managed by this reducer. Specifically, in the reducer I will show below, I need access to the accountDetails.stateOfResidenceId
field.
我有一个减速器,为了计算新状态,我需要来自动作的数据以及来自不由该减速器管理的状态的一部分的数据。具体来说,在我将在下面展示的减速器中,我需要访问该accountDetails.stateOfResidenceId
字段。
initialState.js:
初始状态.js:
export default {
accountDetails: {
stateOfResidenceId: '',
accountType: '',
accountNumber: '',
product: ''
},
forms: {
blueprints: [
]
}
};
formsReducer.js:
formsReducer.js:
import * as types from '../constants/actionTypes';
import objectAssign from 'object-assign';
import initialState from './initialState';
import formsHelper from '../utils/FormsHelper';
export default function formsReducer(state = initialState.forms, action) {
switch (action.type) {
case types.UPDATE_PRODUCT: {
//I NEED accountDetails.stateOfResidenceId HERE
console.log(state);
const formBlueprints = formsHelper.getFormsByProductId(action.product.id);
return objectAssign({}, state, {blueprints: formBlueprints});
}
default:
return state;
}
}
index.js (root reducer):
index.js(根减速器):
import { combineReducers } from 'redux';
import accountDetails from './accountDetailsReducer';
import forms from './formsReducer';
const rootReducer = combineReducers({
accountDetails,
forms
});
export default rootReducer;
How can I access this field?
如何访问此字段?
回答by Crysfel
I would use thunkfor this, here's an example:
我会为此使用thunk,这是一个例子:
export function updateProduct(product) {
return (dispatch, getState) => {
const { accountDetails } = getState();
dispatch({
type: UPDATE_PRODUCT,
stateOfResidenceId: accountDetails.stateOfResidenceId,
product,
});
};
}
Basically you get all the data you need on the action, then you can send that data to your reducer.
基本上,您获得了操作所需的所有数据,然后您可以将该数据发送到您的减速器。
回答by markerikson
Your options are to either write more logic besides just use of combineReducers
, or include more data in the action. The Redux FAQ covers this topic:
您的选择是在仅使用 之外编写更多逻辑combineReducers
,或者在操作中包含更多数据。Redux FAQ 涵盖了这个主题:
https://redux.js.org/faq/reducers/
https://redux.js.org/faq/reducers/
Also, I'm currently working on a new set of pages to the Redux docs on the topic of "Structuring Reducers", which you may find helpful. The current WIP pages are at https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md.
另外,我目前正在研究 Redux 文档的一组新页面,主题是“结构化减速器”,您可能会发现这些页面会有所帮助。当前 WIP 页面位于https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md。
回答by user3377090
I'm not sure if this approach is an anti-pattern but it worked for me. Use a curried function in your actions.
我不确定这种方法是否是一种反模式,但它对我有用。在您的操作中使用柯里化函数。
export const myAction = (actionData) => (dispatch, getState) => {
dispatch({
type: 'SOME_ACTION_TYPE',
data: actionData,
state: getState()
});
}
回答by GhostEcho
It is simple to write your own combine function that does exactly what you want:
编写自己的组合函数很简单,它完全符合您的要求:
import accountDetails from './accountDetailsReducer';
import forms from './formsReducer';
const rootReducer = (state, action) => {
const newState = {};
newState.accountDetails = accountDetails(state.accountDetails, action);
newState.forms = forms(state.forms, action, state.accountDetails);
return newState;
};
export default rootReducer;
Your FormReducer would then be:
您的 FormReducer 将是:
export default function formsReducer(state = initialState.forms, action, accountDetails) {
The formsReducer now has access to the accountDetails.
formsReducer 现在可以访问 accountDetails。
The benefit of this approach is that you only expose the slices of state the you need, instead of the entire state.
这种方法的好处是你只公开你需要的状态片,而不是整个状态。
回答by Sam96
An alternative way, if you use react-redux and need that action only in one place OR are fine with creating an HOC (Higher oder component, dont really need to understand that the important stuff is that this might bloat your html) everywhere you need that access is to use mergepropswith the additional parameters being passed to the action:
另一种方法,如果您使用 react-redux 并且只需要在一个地方执行该操作,或者可以在您需要的任何地方创建 HOC(更高的 oder 组件,并不需要真正了解重要的是这可能会使您的 html 膨胀)该访问是使用带有传递给操作的附加参数的mergeprops:
const mapState = ({accountDetails: {stateOfResidenceId}}) => stateOfResidenceId;
const mapDispatch = (dispatch) => ({
pureUpdateProduct: (stateOfResidenceId) => dispatch({ type: types.UPDATE_PRODUCT, payload: stateOfResidenceId })
});
const mergeProps = (stateOfResidenceId, { pureUpdateProduct}) => ({hydratedUpdateProduct: () => pureUpdateProduct(stateOfResidenceId )});
const addHydratedUpdateProduct = connect(mapState, mapDispatch, mergeProps)
export default addHydratedUpdateProduct(ReactComponent);
export const OtherHydratedComponent = addHydratedUpdateProduct(OtherComponent)
When you use mergeProps what you return there will be added to the props, mapState and mapDispatch will only serve to provide the arguments for mergeProps. So, in other words, this function will add this to your component props (typescript syntax):
当您使用 mergeProps 时,您返回的内容将被添加到道具中,mapState 和 mapDispatch 将仅用于为 mergeProps 提供参数。因此,换句话说,此函数会将其添加到您的组件道具中(打字稿语法):
{hydratedUpdateProduct: () => void}
(take note that the function actually returns the action itself and not void, but you'll ignore that in most cases).
(请注意,该函数实际上返回的是操作本身而不是 void,但在大多数情况下您会忽略它)。
But what you can do is:
但是你可以做的是:
const mapState = ({ accountDetails }) => accountDetails;
const mapDispatch = (dispatch) => ({
pureUpdateProduct: (stateOfResidenceId) => dispatch({ type: types.UPDATE_PRODUCT, payload: stateOfResidenceId })
otherAction: (param) => dispatch(otherAction(param))
});
const mergeProps = ({ stateOfResidenceId, ...passAlong }, { pureUpdateProduct, ... otherActions}) => ({
...passAlong,
...otherActions,
hydratedUpdateProduct: () => pureUpdateProduct(stateOfResidenceId ),
});
const reduxPropsIncludingHydratedAction= connect(mapState, mapDispatch, mergeProps)
export default reduxPropsIncludingHydratedAction(ReactComponent);
this will provide the following stuff to the props:
这将为道具提供以下内容:
{
hydratedUpdateProduct: () => void,
otherAction: (param) => void,
accountType: string,
accountNumber: string,
product: string,
}
On the whole though the complete dissaproval the redux-maintainers show to expanding the functionality of their package to include such wishes in a good way, which would create a pattern for these functionalities WITHOUT supporting fragmentation of the ecosystem, is impressive.
总的来说,尽管 redux 维护者完全反对扩展他们的包的功能以包含这样的愿望,这将为这些功能创建一个模式而不支持生态系统的碎片化,但令人印象深刻。
Packages like Vuex that are not so stubborn dont have nearly so many issues with people abusing antipatterns because they get lost, while supporting a way cleaner syntax with less boilerplate than you'll ever archive with redux and the best supporting packages. And despite the package being way more versatile the documantation is easier to understand because they dont get lost in the details like reduxs documentation tends to do.
像 Vuex 这样不那么顽固的包不会有那么多人滥用反模式因为他们迷路了,同时支持一种更简洁的语法,比使用 redux 和最佳支持包存档的样板更少。尽管该包更加通用,但文档更容易理解,因为它们不会像 reduxs 文档那样迷失在细节中。
回答by miles_christian
You can try to use:
您可以尝试使用:
Which allows you to get state anywhere in your code like so:
这允许您在代码中的任何位置获取状态,如下所示:
const localState1 = getState(reducerA.state1)
const localState2 = getState(reducerB.state2)
But think first if it would be better to pass the external state as a payload in the action.
但首先考虑是否将外部状态作为操作中的有效负载传递会更好。
回答by Xing Wang
I sugguest that you pass it into the action creator. So someplace you'll have an action creator that does something like this:
我建议您将其传递给动作创建者。所以在某个地方你会有一个动作创建者,它会做这样的事情:
updateProduct(arg1, arg2, stateOfResidenceId) {
return {
type: UPDATE_PRODUCT,
stateOfResidenceId
}
}
At the place where you trigger the action, assume you are using react, you can use
在触发动作的地方,假设你使用的是react,你可以使用
function mapStateToProps(state, ownProps) {
return {
stateOfResidenceId: state.accountdetails.stateOfResidenceId
}
}
and connect to your react component using the react-redux's connect.
并使用 react-redux 的连接连接到你的反应组件。
connect(mapStateToProps)(YourReactComponent);
Now, in your react component where you trigger the action updateProduct, you should have the stateOfResidenceId as a prop, and you can pass it to your action creator.
现在,在您触发操作 updateProduct 的反应组件中,您应该将 stateOfResidenceId 作为道具,并且您可以将其传递给您的操作创建者。
It sounds convoluted, but it is really about separation of concerns.
这听起来令人费解,但实际上是关于关注点分离。
回答by ddavy
While dispatching an action, you can pass a parameter. In this case, you could pass accountDetails.stateOfResidenceId
to the action and then pass it on to the reducer as payload.
在分派动作时,您可以传递一个参数。在这种情况下,您可以传递accountDetails.stateOfResidenceId
给操作,然后将其作为有效负载传递给减速器。