Tenho um redutor e, para calcular o novo estado, preciso de dados da ação e também de dados de uma parte do estado não gerenciada por esse redutor. Especificamente, no redutor que mostrarei abaixo, preciso acessar o accountDetails.stateOfResidenceId
campo.
initialState.js:
export default {
accountDetails: {
stateOfResidenceId: '',
accountType: '',
accountNumber: '',
product: ''
},
forms: {
blueprints: [
]
}
};
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 (redutor de raiz):
import { combineReducers } from 'redux';
import accountDetails from './accountDetailsReducer';
import forms from './formsReducer';
const rootReducer = combineReducers({
accountDetails,
forms
});
export default rootReducer;
Como posso acessar este campo?
javascript
reactjs
redux
Kibowki
fonte
fonte
Respostas:
Eu usaria thunk para isso, aqui está um exemplo:
export function updateProduct(product) { return (dispatch, getState) => { const { accountDetails } = getState(); dispatch({ type: UPDATE_PRODUCT, stateOfResidenceId: accountDetails.stateOfResidenceId, product, }); }; }
Basicamente, você obtém todos os dados de que precisa sobre a ação e, em seguida, pode enviar esses dados ao seu redutor.
fonte
Suas opções são escrever mais lógica além de apenas usar
combineReducers
ou incluir mais dados na ação. O Redux FAQ cobre este tópico:https://redux.js.org/faq/reducers/
Além disso, estou atualmente trabalhando em um novo conjunto de páginas para os documentos do Redux no tópico "Estruturação de redutores", que você pode achar útil. As páginas WIP atuais estão em https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md .
fonte
thunk
. Você acha que essa seria uma boa solução para o meu problema? Se isso vai bagunçar meu código ou não é uma prática recomendada, não é uma solução que desejo buscar, mas não me sinto bem informado para determinar os efeitos de longo prazo dessas escolhas.Não tenho certeza se essa abordagem é um antipadrão, mas funcionou para mim. Use uma função curried em suas ações.
export const myAction = (actionData) => (dispatch, getState) => { dispatch({ type: 'SOME_ACTION_TYPE', data: actionData, state: getState() }); }
fonte
É simples escrever sua própria função de combinação que faz exatamente o que você deseja:
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;
Seu FormReducer seria então:
export default function formsReducer(state = initialState.forms, action, accountDetails) {
O formsReducer agora tem acesso a accountDetails.
O benefício dessa abordagem é que você só expõe as fatias de estado de que precisa, em vez de todo o estado.
fonte
Sugiro que você passe para o criador da ação. Então, em algum lugar você terá um criador de ação que faz algo assim:
updateProduct(arg1, arg2, stateOfResidenceId) { return { type: UPDATE_PRODUCT, stateOfResidenceId } }
No local onde você aciona a ação, suponha que esteja usando o react, você pode usar
function mapStateToProps(state, ownProps) { return { stateOfResidenceId: state.accountdetails.stateOfResidenceId } }
e conecte-se ao seu componente react usando a conexão react-redux.
Agora, em seu componente de reação onde você aciona a ação updateProduct, você deve ter o stateOfResidenceId como um suporte e pode passá-lo para o criador da ação.
Parece complicado, mas na verdade se trata de separação de interesses.
fonte
Você pode tentar usar:
redux-nomeados-redutores
O que permite que você obtenha o estado em qualquer lugar em seu código, como:
const localState1 = getState(reducerA.state1) const localState2 = getState(reducerB.state2)
Mas pense primeiro se seria melhor passar o estado externo como uma carga útil na ação.
fonte
Uma maneira alternativa, se você usar o react-redux e precisar dessa ação apenas em um lugar OU está bem com a criação de um HOC (componente superior de oder, realmente não precisa entender que o importante é que isso pode inchar seu html) em todos os lugares que você precisar esse acesso é para usar mergeprops com os parâmetros adicionais sendo passados para a ação:
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)
Quando você usa mergeProps, o que você retorna será adicionado aos props, mapState e mapDispatch servirão apenas para fornecer os argumentos para mergeProps. Então, em outras palavras, esta função irá adicionar isso aos seus componentes (sintaxe de texto digitado):
{hydratedUpdateProduct: () => void}
(observe que a função realmente retorna a própria ação e não nula, mas você irá ignorar isso na maioria dos casos).
Mas o que você pode fazer é:
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);
isso fornecerá o seguinte material aos adereços:
{ hydratedUpdateProduct: () => void, otherAction: (param) => void, accountType: string, accountNumber: string, product: string, }
No geral, embora a desaprovação completa dos redux-mantenedores mostram para expandir a funcionalidade de seu pacote para incluir tais desejos de uma boa maneira, o que criaria um padrão para essas funcionalidades SEM apoiar a fragmentação do ecossistema, é impressionante.
Pacotes como o Vuex, que não são tão teimosos, não têm tantos problemas com pessoas abusando de antipadrões porque eles se perdem, ao mesmo tempo em que oferecem uma sintaxe mais limpa com menos clichê do que você jamais arquivará com redux e os melhores pacotes de suporte. E apesar do pacote ser muito mais versátil, a documentação é mais fácil de entender porque eles não se perdem nos detalhes como a documentação do redux tende a fazer.
fonte
Ao despachar uma ação, você pode passar um parâmetro. Nesse caso, você poderia passar
accountDetails.stateOfResidenceId
para a ação e depois passá-la para o redutor como carga útil.fonte