จะเข้าถึงสถานะภายใน Redux reducer ได้อย่างไร


88

ฉันมีตัวลดและในการคำนวณสถานะใหม่ฉันต้องการข้อมูลจากการกระทำและข้อมูลจากส่วนหนึ่งของสถานะที่ไม่ได้จัดการโดยตัวลดนี้ โดยเฉพาะในตัวลดที่ฉันจะแสดงด้านล่างฉันต้องการเข้าถึงaccountDetails.stateOfResidenceIdฟิลด์

initialState.js:

export default {
    accountDetails: {
        stateOfResidenceId: '',
        accountType: '',
        accountNumber: '',
        product: ''
    },
    forms: {
        blueprints: [

        ]
    }
};

formReducer.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;
  }
}

ดัชนี js (ตัวลดรูท):

import { combineReducers } from 'redux';
import accountDetails from './accountDetailsReducer';
import forms from './formsReducer';

const rootReducer = combineReducers({
    accountDetails,
    forms
});

export default rootReducer;

ฉันจะเข้าถึงช่องนี้ได้อย่างไร?



8
คำพูดนั้นไม่สมเหตุสมผลเลย จุดรวมของฟังก์ชันลดคือคุณตัดสินใจตามสถานะปัจจุบันและการกระทำ
markerikson

คำตอบ:


105

ฉันจะใช้thunkสำหรับสิ่งนี้นี่คือตัวอย่าง:

export function updateProduct(product) {
  return (dispatch, getState) => {
    const { accountDetails } = getState();

    dispatch({
      type: UPDATE_PRODUCT,
      stateOfResidenceId: accountDetails.stateOfResidenceId,
      product,
    });
  };
}

โดยทั่วไปคุณจะได้รับข้อมูลทั้งหมดที่คุณต้องการในการดำเนินการจากนั้นคุณสามารถส่งข้อมูลนั้นไปยังตัวลดของคุณ


4
มีความคิดว่าทำไมสถานะปัจจุบันจึงไม่ถูกลดโดยREDUXเอง .. ? ดูเหมือนจะแปลกที่เมื่อจัดส่งฉันต้องเพิ่มสิ่งที่ไม่เกี่ยวข้องลงในตัวลดเพื่อให้สถานะเริ่มต้นไม่แทนที่สถานะปัจจุบันของสิ่งอื่น ๆ ที่ไม่เกี่ยวข้องกับการโทรจัดส่งปัจจุบัน
vsync

10

ตัวเลือกของคุณคือเขียนตรรกะเพิ่มเติมนอกเหนือจากการใช้combineReducersหรือรวมข้อมูลเพิ่มเติมในการดำเนินการ คำถามที่พบบ่อยของ Redux ครอบคลุมหัวข้อนี้:

https://redux.js.org/faq/reducers/

นอกจากนี้ฉันกำลังดำเนินการชุดหน้าใหม่ของเอกสาร Redux ในหัวข้อ "Structuring Reducers" ซึ่งคุณอาจพบว่ามีประโยชน์ หน้า WIP ปัจจุบันอยู่ที่https://github.com/markerikson/redux/blob/structuring-reducers-page/docs/recipes/StructuringReducers.md


ขอบคุณสำหรับคำตอบ. ฉันได้สำรวจแหล่งข้อมูลบางส่วนที่คุณเชื่อมโยงแล้วและจะดำเนินการต่อไป อย่างไรก็ตามคำถามสำหรับคุณเนื่องจากคุณดูเหมือนจะมีความรู้ คำตอบอื่นแนะนำการใช้thunk. คุณคิดว่านี่จะเป็นทางออกที่ดีสำหรับปัญหาของฉันหรือไม่? หากจะทำให้โค้ดของฉันยุ่งเหยิงหรือไม่ใช่แนวทางปฏิบัติที่ดีที่สุดมันไม่ใช่วิธีแก้ปัญหาที่ฉันต้องการติดตาม แต่ฉันรู้สึกไม่มีความรู้เพียงพอที่จะกำหนดผลกระทบในระยะยาวของตัวเลือกเหล่านี้
kibowki

3
ใช่ thunks เป็นแนวทางพื้นฐานมาตรฐานในการจัดการผลข้างเคียงและการดำเนินการตรรกะที่ซับซ้อนซึ่งเกี่ยวข้องกับการจัดส่งหลายครั้งและการใช้สถานะแอปปัจจุบัน เป็นเรื่องปกติโดยสิ้นเชิงที่จะเขียนฟังก์ชัน thunk ที่อ่านสถานะแอปปัจจุบันและทำสิ่งต่างๆเช่นจัดส่งแบบมีเงื่อนไขส่งการดำเนินการหลายรายการหรือคว้าส่วนหนึ่งของรัฐและรวมถึงสิ่งนั้นในการดำเนินการที่จัดส่ง ผมมีตัวอย่างบางส่วนของรูปแบบ thunk สามัญgist.github.com/markerikson/ea4d0a6ce56ee479fe8b356e099f857e
markerikson

2

ฉันไม่แน่ใจว่าแนวทางนี้เป็นการต่อต้านรูปแบบหรือไม่ แต่ได้ผลสำหรับฉัน ใช้ฟังก์ชัน curried ในการกระทำของคุณ

export const myAction = (actionData) => (dispatch, getState) => {
   dispatch({
      type: 'SOME_ACTION_TYPE',
      data: actionData,
      state: getState()
   });
}

1

เป็นเรื่องง่ายที่จะเขียนฟังก์ชันการรวมของคุณเองที่ทำสิ่งที่คุณต้องการ:

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 ได้แล้ว

ประโยชน์ของแนวทางนี้คือคุณเปิดเผยเฉพาะส่วนของสถานะที่คุณต้องการแทนที่จะเป็นทั้งรัฐ


0

ฉันขอแนะนำให้คุณส่งต่อไปยังผู้สร้างการกระทำ ดังนั้นบางแห่งคุณจะมีผู้สร้างแอ็คชั่นที่ทำสิ่งนี้:

updateProduct(arg1, arg2, stateOfResidenceId) {
  return {
    type: UPDATE_PRODUCT,
    stateOfResidenceId
  }
}

ณ สถานที่ที่คุณกระตุ้นการกระทำสมมติว่าคุณกำลังใช้การตอบสนองคุณสามารถใช้ได้

function mapStateToProps(state, ownProps) {
  return {
    stateOfResidenceId: state.accountdetails.stateOfResidenceId
  }  
}

และเชื่อมต่อกับส่วนประกอบปฏิกิริยาของคุณโดยใช้การเชื่อมต่อของ react-redux

connect(mapStateToProps)(YourReactComponent);

ตอนนี้ในองค์ประกอบการตอบสนองของคุณที่คุณเรียกใช้การดำเนินการ updateProduct คุณควรมี stateOfResidenceId เป็นเสาและคุณสามารถส่งต่อไปยังผู้สร้างการกระทำของคุณได้

ฟังดูสับสน แต่จริงๆแล้วมันเกี่ยวกับการแยกความกังวล


0

คุณสามารถลองใช้:

ตัวลดชื่อ redux

ซึ่งช่วยให้คุณได้รับสถานะที่ใดก็ได้ในรหัสของคุณดังนี้:

const localState1 = getState(reducerA.state1)
const localState2 = getState(reducerB.state2)

แต่คิดก่อนว่ามันจะดีกว่าไหมที่จะส่งผ่านสถานะภายนอกมาเป็นเพย์โหลดในการดำเนินการ


0

อีกทางเลือกหนึ่งหากคุณใช้ react-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 เท่านั้น กล่าวอีกนัยหนึ่งฟังก์ชันนี้จะเพิ่มสิ่งนี้ให้กับอุปกรณ์ประกอบฉากของคุณ (ไวยากรณ์ typescript):

{hydratedUpdateProduct: () => 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 และแพ็คเกจสนับสนุนที่ดีที่สุด และแม้ว่าแพ็คเกจจะมีความหลากหลายมากขึ้น แต่เอกสารก็ยังเข้าใจได้ง่ายกว่าเพราะพวกเขาไม่หลงทางในรายละเอียดเช่นเอกสารซ้ำซ้อนมีแนวโน้มที่จะทำ


-1

ในขณะที่ส่งการดำเนินการคุณสามารถส่งผ่านพารามิเตอร์ ในกรณีนี้คุณสามารถส่งผ่านaccountDetails.stateOfResidenceIdไปยังการดำเนินการแล้วส่งต่อไปยังตัวลดเป็นน้ำหนักบรรทุก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.