У меня есть редуктор, и для расчета нового состояния мне нужны данные из действия, а также данные из части состояния, не управляемой этим редуктором. В частности, в редукторе, который я покажу ниже, мне нужен доступ к accountDetails.stateOfResidenceId
полю.
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 (корневой редуктор):
import { combineReducers } from 'redux';
import accountDetails from './accountDetailsReducer';
import forms from './formsReducer';
const rootReducer = combineReducers({
accountDetails,
forms
});
export default rootReducer;
Как я могу получить доступ к этому полю?
javascript
reactjs
redux
Twilco
источник
источник
Ответы:
Я бы использовал для этого thunk , вот пример:
export function updateProduct(product) { return (dispatch, getState) => { const { accountDetails } = getState(); dispatch({ type: UPDATE_PRODUCT, stateOfResidenceId: accountDetails.stateOfResidenceId, product, }); }; }
По сути, вы получаете все необходимые данные о действии, а затем можете отправить эти данные своему редуктору.
источник
Вы можете либо написать больше логики помимо простого использования
combineReducers
, либо включить больше данных в действие. Redux FAQ охватывает эту тему:https://redux.js.org/faq/reducers/
Кроме того, в настоящее время я работаю над новым набором страниц документации Redux по теме «Структурирование редукторов», которые могут быть вам полезны. Текущие страницы WIP находятся по адресу https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md .
источник
thunk
. Как вы думаете, это будет хорошим решением моей проблемы? Если это приведет к беспорядку в моем коде или это не лучшая практика, это не то решение, которое я хочу искать, но я не чувствую себя достаточно осведомленным, чтобы определить долгосрочные последствия этого выбора.Я не уверен, что этот подход является антипаттерном, но у меня он сработал. Используйте в своих действиях каррированную функцию.
export const myAction = (actionData) => (dispatch, getState) => { dispatch({ type: 'SOME_ACTION_TYPE', data: actionData, state: getState() }); }
источник
Написать свою собственную функцию комбинирования, которая будет делать именно то, что вы хотите, просто:
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;
Тогда ваш FormReducer будет:
export default function formsReducer(state = initialState.forms, action, accountDetails) {
FormReducer теперь имеет доступ к accountDetails.
Преимущество этого подхода в том, что вы предоставляете только нужные вам фрагменты состояния, а не все состояние.
источник
Я предлагаю вам передать его в создатель действий. Итак, где-нибудь у вас будет создатель действий, который делает что-то вроде этого:
updateProduct(arg1, arg2, stateOfResidenceId) { return { type: UPDATE_PRODUCT, stateOfResidenceId } }
Предположим, вы используете реакцию в том месте, где вы запускаете действие, вы можете использовать
function mapStateToProps(state, ownProps) { return { stateOfResidenceId: state.accountdetails.stateOfResidenceId } }
и подключитесь к вашему компоненту реакции с помощью connect-redux.
Теперь в вашем компоненте реакции, где вы запускаете действие updateProduct, вы должны иметь stateOfResidenceId в качестве опоры, и вы можете передать его своему создателю действия.
Это звучит запутанно, но на самом деле речь идет о разделении интересов.
источник
Вы можете попробовать использовать:
redux-named-redurs
Это позволяет вам получить состояние в любом месте вашего кода следующим образом:
const localState1 = getState(reducerA.state1) const localState2 = getState(reducerB.state2)
Но сначала подумайте, не было бы лучше передать внешнее состояние в качестве полезной нагрузки в действии.
источник
Альтернативный способ, если вы используете response-redux и нуждаетесь в этом действии только в одном месте ИЛИ все в порядке с созданием HOC (компонент более высокого уровня, на самом деле не нужно понимать, что важно то, что это может раздувать ваш 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)
Когда вы используете mergeProps, то, что вы возвращаете, будет добавлено к реквизитам, mapState и mapDispatch будут служить только для предоставления аргументов для mergeProps. Другими словами, эта функция добавит это в свойства вашего компонента (синтаксис машинописного текста):
{hydratedUpdateProduct: () => void}
(обратите внимание, что функция фактически возвращает само действие, а не void, но в большинстве случаев вы проигнорируете это).
Но вы можете:
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);
это предоставит реквизитам следующее:
{ hydratedUpdateProduct: () => void, otherAction: (param) => void, accountType: string, accountNumber: string, product: string, }
В целом, хотя полное несогласие разработчиков redux с расширением функциональности своего пакета для правильного включения таких пожеланий, которые могли бы создать шаблон для этих функций БЕЗ поддержки фрагментации экосистемы, впечатляет.
Пакеты вроде Vuex, которые не столь упрямы, не имеют почти такого количества проблем с людьми, злоупотребляющими антипаттернами из-за того, что они теряются, при этом поддерживая более чистый синтаксис с меньшим количеством шаблонов, чем вы когда-либо архивируете с помощью redux и лучших поддерживающих пакетов. И, несмотря на то, что пакет более универсален, документацию легче понять, потому что они не теряются в деталях, как это обычно делается в документации по reduxs.
источник
При отправке действия вы можете передать параметр. В этом случае вы можете перейти
accountDetails.stateOfResidenceId
к действию, а затем передать его редуктору в качестве полезной нагрузки.источник