एक्शन क्रिएटर में Redux स्टेट एक्सेस करना?


296

कहो मैं निम्नलिखित है:

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));
  }
}

जवाबों:


521

इस पर अलग-अलग राय है कि एक्शन क्रिएटर्स में एक्सेस करने की स्थिति एक अच्छा विचार है:

  • Redux के निर्माता डैन अब्रामोव को लगता है कि यह सीमित होना चाहिए: "कुछ उपयोग के मामले जहां मुझे लगता है कि यह स्वीकार्य है, कैश्ड डेटा की जाँच करने से पहले आप अनुरोध करें, या यह जाँचने के लिए कि क्या आप प्रमाणित हैं (दूसरे शब्दों में, सशर्त प्रेषण कर रहे हैं)। मुझे लगता है कि गुजर डेटा जैसे state.something.itemsएक कार्रवाई निर्माता में निश्चित रूप से एक विरोधी पैटर्न है और हतोत्साहित किया जाता है, क्योंकि यह परिवर्तन इतिहास छिप: अगर वहाँ एक बग है और itemsगलत हैं, यह पता लगाने के लिए मुश्किल है , जहां उन गलत मान क्योंकि वे कर रहे हैं से आते हैं पहले से ही कार्रवाई का एक हिस्सा है, बजाय एक reducer द्वारा सीधे एक कार्रवाई के जवाब में गणना की। तो यह ध्यान से करते हैं। "
  • वर्तमान Redux अनुचर मार्क Erikson का कहना हैgetState कि यह ठीक है और यहां तक कि थ्रक्स में उपयोग करने के लिए प्रोत्साहित किया जाता है - यही कारण है कि यह मौजूद है । वह अपने ब्लॉग पोस्ट Idiomatic Redux: Thoughts on Thunks, Sagas, Abstraction और Reusability में एक्शन क्रिएटर्स में राज्य तक पहुँचने के पेशेवरों और विपक्षों के बारे में चर्चा करता है ।

यदि आप पाते हैं कि आपको इसकी आवश्यकता है, तो आपके द्वारा सुझाए गए दोनों दृष्टिकोण ठीक हैं। पहले दृष्टिकोण को किसी मिडलवेयर की आवश्यकता नहीं होती है:

import store from '../store';

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

हालाँकि आप देख सकते हैं कि यह storeकुछ मॉड्यूल से निर्यात किए गए सिंगलटन पर निर्भर करता है । हम इसकी अनुशंसा नहीं करते हैं क्योंकि इससे आपके ऐप में सर्वर रेंडरिंग को जोड़ना बहुत कठिन हो जाता है क्योंकि सर्वर पर अधिकांश मामलों में आप अपने अनुरोध के लिए एक अलग स्टोर रखना चाहते हैं । इसलिए जबकि तकनीकी रूप से यह दृष्टिकोण काम करता है, हम किसी मॉड्यूल से स्टोर निर्यात करने की अनुशंसा नहीं करते हैं।

यही कारण है कि हम दूसरे दृष्टिकोण की सलाह देते हैं:

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

    dispatch(anotherAction(items));
  }
}

इसके लिए आपको Redux Thunk मिडलवेयर का उपयोग करना होगा लेकिन यह क्लाइंट और सर्वर दोनों पर ठीक काम करता है। आप Redux Thunk के बारे में अधिक पढ़ सकते हैं और यहां इस मामले में यह क्यों आवश्यक है

आदर्श रूप से, आपके कार्यों को "मोटा" नहीं होना चाहिए और इसमें यथासंभव कम जानकारी होनी चाहिए, लेकिन आपको अपने स्वयं के आवेदन में सबसे अच्छा काम करने के लिए स्वतंत्र महसूस करना चाहिए। Redux FAQ में एक्शन क्रिएटर्स और रिड्यूसर्स के बीच विभाजन के तर्क के बारे में जानकारी होती है और जब यह getStateएक्शन क्रिएटर में उपयोग करने के लिए उपयोगी हो सकता है


5
मेरे पास एक स्थिति है जब एक घटक में कुछ का चयन एक PUT या POST को ट्रिगर कर सकता है, यह निर्भर करता है कि स्टोर में घटक से संबंधित डेटा है या नहीं। क्या ठग आधारित एक्शन क्रिएटर के बजाय घटक में PUT / POST चयन के लिए व्यावसायिक तर्क रखना बेहतर है?
vicusbass

3
सबसे अच्छा अभ्यास क्या है? मैं अब इसी तरह की समस्या का सामना कर रहा हूं जहां मैं अपने एक्शन क्रिएटर में गेटस्टेट का उपयोग कर रहा हूं। मेरे मामले में मैं यह निर्धारित करने के लिए इसका उपयोग करता हूं कि क्या मानों में यदि किसी प्रपत्र में परिवर्तन लंबित हैं (और यदि ऐसा है तो मैं एक कार्रवाई को भेजूंगा जो एक संवाद दिखाता है)।
Arne H. Bitubekk

42
एक्शन क्रिएटर में स्टोर से पढ़ना ठीक है। मैं आपको एक चयनकर्ता का उपयोग करने के लिए प्रोत्साहित करूंगा ताकि आप सटीक राज्य आकार पर निर्भर न हों।
दान अब्रामोव

2
मैं मिक्सडेल को डेटा भेजने के लिए एक मिडलवेयर का उपयोग कर रहा हूं। इसलिए मेरे पास कार्रवाई के अंदर एक मेटा कुंजी है। मुझे राज्य से मिक्सडेल तक अलग-अलग चर में जाने की आवश्यकता है। उन्हें एक्शन क्रिएटर्स पर सेट करना एक एंटी-पैटर्न लगता है। इस तरह के उपयोग के मामलों को संभालने के लिए सबसे अच्छा तरीका क्या होगा?
आकाश सिगडेल

2
ओह यार! मैंने getStateदूसरे पैरामीटर के रूप में उस
रिक्स थंक

33

जब आपका परिदृश्य सरल होता है तो आप उपयोग कर सकते हैं

import store from '../store';

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

लेकिन कभी-कभी आपकी action creatorआवश्यकता को बहु कार्यों को ट्रिगर करने की आवश्यकता होती है

उदाहरण के लिए async अनुरोध इसलिए आपको REQUEST_LOAD REQUEST_LOAD_SUCCESS REQUEST_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
                });
            }
        })
    }
}

नोट: आपको एक्शन क्रिएटर में फंक्शन लौटाने के लिए रेडक्स-थंक की आवश्यकता है


3
क्या मैं सिर्फ यह पूछ सकता हूं कि क्या राज्य के 'लोडिंग' की स्थिति पर कोई जांच होनी चाहिए ताकि दूसरा अजाक्स अनुरोध न हो, जबकि पहले खत्म हो रहा है?
जोईडेई

@JoeTidee उदाहरण में लोडिंग राज्य का प्रेषण किया जाता है। यदि आप उदाहरण के लिए बटन के साथ यह क्रिया करते हैं, तो आप loading === trueजाँचेंगे कि क्या बटन अक्षम है या नहीं।
croraf

4

मैं @Bloomca से सहमत हूं। स्टोर से प्रेषण फ़ंक्शन में आवश्यक मान पास करना तर्क के रूप में स्टोर निर्यात करने की तुलना में सरल लगता है। मैंने यहाँ एक उदाहरण दिया:

import React from "react";
import {connect} from "react-redux";
import * as actions from '../actions';

class App extends React.Component {

  handleClick(){
    const data = this.props.someStateObject.data;
    this.props.someDispatchFunction(data);
  }

  render(){
    return (
      <div>       
      <div onClick={ this.handleClick.bind(this)}>Click Me!</div>      
      </div>
    );
  }
}


const mapStateToProps = (state) => {
  return { someStateObject: state.someStateObject };
};

const mapDispatchToProps = (dispatch) => {
  return {
    someDispatchFunction:(data) => { dispatch(actions.someDispatchFunction(data))},

  };
}


export default connect(mapStateToProps, mapDispatchToProps)(App);

यह विधि काफी तार्किक है।
अहमत ekimşek

यह करने का सही तरीका है और मैं इसे कैसे करता हूं। आपके एक्शन-निर्माता को पूरे राज्य को जानने की आवश्यकता नहीं है, केवल वह बिट जो इसके लिए प्रासंगिक है।
ऐश

3

मैं यह बताना चाहूंगा कि यह स्टोर से पढ़ने के लिए उतना बुरा नहीं है - यह तय करना अधिक सुविधाजनक हो सकता है कि स्टोर के आधार पर क्या किया जाना चाहिए, घटक को सब कुछ पास करने की तुलना में और फिर एक पैरामीटर के रूप में एक समारोह। मैं पूरी तरह से डैन से सहमत हूँ, कि जब तक आप 100% सुनिश्चित नहीं हो जाते कि आप केवल क्लाइंट-साइड रेंडरिंग के लिए उपयोग करेंगे (अन्यथा बग्स का पता लगाना मुश्किल हो सकता है) का उपयोग न करें तो बेहतर है।

मैंने Redux की वाचालता से निपटने के लिए हाल ही में एक पुस्तकालय बनाया है , और मुझे लगता है कि यह सब कुछ मिडलवेयर में डालना एक अच्छा विचार है, इसलिए आपके पास आश्रितता इंजेक्शन के रूप में हर एक है।

तो, आपका उदाहरण ऐसा दिखेगा:

import { createSyncTile } from 'redux-tiles';

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

हालाँकि, जैसा कि आप देख सकते हैं, हम वास्तव में यहां डेटा को संशोधित नहीं करते हैं, इसलिए एक अच्छा मौका है कि हम इस चयनकर्ता का उपयोग दूसरी जगह पर इसे कहीं और संयोजित करने के लिए कर सकते हैं।


1

इसे हल करने का एक वैकल्पिक तरीका पेश करना। यह आपके आवेदन के आधार पर डैन के समाधान से बेहतर या खराब हो सकता है।

आप 2 अलग-अलग कार्यों में कार्रवाई को विभाजित करके राज्य को रिड्यूसर से प्राप्त कर सकते हैं: पहले डेटा के लिए पूछें, डेटा पर दूसरा कार्य करें। आप इसका उपयोग करके कर सकते हैं redux-loop

पहले 'कृपया डेटा के लिए पूछें'

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

Reducer में, पूछें को रोकें और डेटा का उपयोग करके दूसरे चरण की कार्रवाई को प्रदान करें redux-loop

import { loop, Cmd } from 'redux-loop';
const initialState = { data: '' }
export default (state=initialState, action) => {
    switch(action.type) {
        case SOME_ACTION: {
            return loop(state, Cmd.action(anotherAction(state.data))
        }
    }
}

हाथ में डेटा के साथ, जो कुछ भी आप शुरू में चाहते थे

export const ANOTHER_ACTION = 'ANOTHER_ACTION';
export function anotherAction(data) {
    return {
        type: ANOTHER_ACTION,
        payload: data,
    }
}

आशा है कि यह किसी की मदद करता है।


0

मुझे पता है कि मुझे यहां पार्टी करने में देर हो रही है, लेकिन मैं यहां खुद को कार्रवाई में राज्य का उपयोग करने की इच्छा के लिए आया था, और फिर अपना खुद का गठन किया, जब मुझे एहसास हुआ कि मुझे क्या लगता है कि यह सही व्यवहार है।

यह वह जगह है जहां एक चयनकर्ता मेरे लिए सबसे अधिक समझ में आता है। आपका घटक जो इस अनुरोध को जारी करता है, उसे बताया जाना चाहिए कि चयन के माध्यम से इसे जारी करने का समय है।

export const SOME_ACTION = 'SOME_ACTION';
export function someAction(items) {
  return (dispatch) => {
    dispatch(anotherAction(items));
  }
}

यह महसूस कर सकता है जैसे कि अमूर्त रिसाव हो रहा है, लेकिन आपके घटक को स्पष्ट रूप से संदेश भेजने की आवश्यकता है और संदेश पेलोड में उचित स्थिति होनी चाहिए। दुर्भाग्य से आपके प्रश्न का कोई ठोस उदाहरण नहीं है क्योंकि हम चयनकर्ताओं और कार्यों के 'बेहतर मॉडल' के माध्यम से काम कर सकते हैं।


0

मैं अभी तक एक और विकल्प का सुझाव देना चाहूंगा जो मुझे सबसे साफ लगता है, लेकिन इसके लिए react-reduxकुछ या कुछ अनुकरणीय होना चाहिए - साथ ही मैं कुछ अन्य फैंसी विशेषताओं का भी उपयोग कर रहा हूं:

// actions.js
export const someAction = (items) => ({
    type: 'SOME_ACTION',
    payload: {items},
});
// Component.jsx
import {connect} from "react-redux";

const Component = ({boundSomeAction}) => (<div
    onClick={boundSomeAction}
/>);

const mapState = ({otherReducer: {items}}) => ({
    items,
});

const mapDispatch = (dispatch) => bindActionCreators({
    someAction,
}, dispatch);

const mergeProps = (mappedState, mappedDispatches) => {
    // you can only use what gets returned here, so you dont have access to `items` and 
    // `someAction` anymore
    return {
        boundSomeAction: () => mappedDispatches.someAction(mappedState.items),
    }
});

export const ConnectedComponent = connect(mapState, mapDispatch, mergeProps)(Component);
// (with  other mapped state or dispatches) Component.jsx
import {connect} from "react-redux";

const Component = ({boundSomeAction, otherAction, otherMappedState}) => (<div
    onClick={boundSomeAction}
    onSomeOtherEvent={otherAction}
>
    {JSON.stringify(otherMappedState)}
</div>);

const mapState = ({otherReducer: {items}, otherMappedState}) => ({
    items,
    otherMappedState,
});

const mapDispatch = (dispatch) => bindActionCreators({
    someAction,
    otherAction,
}, dispatch);

const mergeProps = (mappedState, mappedDispatches) => {
    const {items, ...remainingMappedState} = mappedState;
    const {someAction, ...remainingMappedDispatch} = mappedDispatch;
    // you can only use what gets returned here, so you dont have access to `items` and 
    // `someAction` anymore
    return {
        boundSomeAction: () => someAction(items),
        ...remainingMappedState,
        ...remainingMappedDispatch,
    }
});

export const ConnectedComponent = connect(mapState, mapDispatch, mergeProps)(Component);

यदि आप इसका पुन: उपयोग करना चाहते हैं, तो आपको विशिष्ट को निकालना होगा mapState, mapDispatchऔर mergePropsअन्य जगहों पर पुन: उपयोग करने के लिए कार्य करना होगा, लेकिन यह निर्भरता पूरी तरह से स्पष्ट करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.