প্রতিক্রিয়া / Redux - অ্যাপ্লিকেশন লোড / ইনিশ উপর প্রেরণ কর্ম


88

আমার একটি সার্ভার থেকে প্রমাণীকরণের টোকেন রয়েছে, তাই যখন আমার রেডাক্স অ্যাপ্লিকেশনটি প্রাথমিকভাবে লোড করা হয় তখন ব্যবহারকারীকে সত্যায়িত করা হয়েছে কিনা তা যাচাই করার জন্য আমার এই সার্ভারে একটি অনুরোধ করতে হবে এবং হ্যাঁ যদি আমার টোকেন পাওয়া উচিত।

আমি খুঁজে পেয়েছি যে রেডাক্স কোর আইএনআইটি ক্রিয়া ব্যবহারের প্রস্তাব দেওয়া হয় না, সুতরাং অ্যাপ্লিকেশন রেন্ডার করার আগে আমি কীভাবে কোনও ক্রিয়া প্রেরণ করতে পারি?

উত্তর:


78

আপনি রুট componentDidMountপদ্ধতিতে কোনও ক্রিয়া প্রেরণ renderকরতে পারেন এবং পদ্ধতিতে আপনি লেখার স্থিতি যাচাই করতে পারেন।

এটার মতো কিছু:

class App extends Component {
  componentDidMount() {
    this.props.getAuth()
  }

  render() {
    return this.props.isReady
      ? <div> ready </div>
      : <div>not ready</div>
  }
}

const mapStateToProps = (state) => ({
  isReady: state.isReady,
})

const mapDispatchToProps = {
  getAuth,
}

export default connect(mapStateToProps, mapDispatchToProps)(App)

4
আমার componentWillMount()জন্য জিনিস। আমি mapDispatchToProps()App.js এর সমস্ত প্রেরণ সম্পর্কিত ক্রিয়াকলাপকে কল করে একটি সাধারণ ফাংশন সংজ্ঞায়িত করেছি এবং এটিকে কল করেছি componentWillMount()
ফ্রিএক্সএক্স

এটি দুর্দান্ত, তবে মানচিত্রডিসপ্যাচটপ্রপগুলি ব্যবহার করা আরও বর্ণনামূলক বলে মনে হয়। পরিবর্তে ম্যাপস্টেটটোপ্রপস ব্যবহার করার পিছনে আপনার যুক্তি কি?

@ adc17 ওহুপস :) মন্তব্যের জন্য ধন্যবাদ আমি আমার উত্তর পরিবর্তন করেছি!
সেরিহি বারানীউক

4
@ অ্যাডক [mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a dispatch call so they may be invoked directly, will be merged into the component’s props.
সেরিহি বারানিয়ুক

4
এই সমাধানটি প্রয়োগ করার চেষ্টা করার সময় আমি এই ত্রুটিটি পেয়েছিUncaught Error: Could not find "store" in either the context or props of "Connect(App)". Either wrap the root component in a <Provider>, or explicitly pass "store" as a prop to "Connect(App)".
মার্খপস

35

এটির জন্য যে সমাধান দেওয়া হয়েছে তাতে আমি খুশি নই এবং তারপরে এটি আমার কাছে ঘটেছিল যে আমি ক্লাসগুলি রেন্ডার করার প্রয়োজনের বিষয়ে ভাবছিলাম। আমি কী শুরু করার জন্য একটি ক্লাস তৈরি করেছি এবং তারপরে componentDidMountপদ্ধতিগুলিতে জিনিসগুলি ধাক্কা দিয়েছি এবং renderডিসপ্লেতে কেবল একটি লোডিং স্ক্রিন পেয়েছি ?

<Provider store={store}>
  <Startup>
    <Router>
      <Switch>
        <Route exact path='/' component={Homepage} />
      </Switch>
    </Router>
  </Startup>
</Provider>

এবং তারপরে এর মতো কিছু রয়েছে:

class Startup extends Component {
  static propTypes = {
    connection: PropTypes.object
  }
  componentDidMount() {
    this.props.actions.initialiseConnection();
  }
  render() {
    return this.props.connection
      ? this.props.children
      : (<p>Loading...</p>);
  }
}

function mapStateToProps(state) {
  return {
    connection: state.connection
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(Actions, dispatch)
  };
}

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

তারপরে আপনার অ্যাপটিকে আরম্ভ করার জন্য অ্যাসিঙ্কটিতে কিছু রিডেক্স অ্যাকশন লিখুন। একটি ট্রিট কাজ করে।


এখন আমি এর সমাধান খুঁজছি! আমি বিশ্বাস করি এখানে আপনার অন্তর্দৃষ্টি পুরোপুরি সঠিক। ধন্যবাদ
ইয়ানিভিজিকে

29

এখানে সমস্ত উত্তরগুলি মূল উপাদান তৈরি করার এবং এটি উপাদান ডিডমাউন্টে ফায়ার করার ক্ষেত্রে ভিন্নতা বলে মনে হচ্ছে। রিডুএক্স সম্পর্কে আমি যে জিনিসগুলি সবচেয়ে বেশি উপভোগ করি তার মধ্যে একটি হ'ল এটি উপাদান উপাদানগুলি থেকে ডেটা আনার বিষয়টি ডুপ্লুপ করে। এই ক্ষেত্রে এটির চেয়ে আলাদা হওয়া উচিত বলে আমি কোনও কারণ দেখছি না।

আপনি যদি আপনার স্টোরটি মূল index.jsফাইলে আমদানি করে থাকেন তবে আপনি কেবল নিজের অ্যাকশন স্রষ্টাকে প্রেরণ করতে পারেন (আসুন এটি কল করুনinitScript() সেই ফাইলটিতে ) এবং কোনও কিছু লোড হওয়ার আগে তা আগুন ধরিয়ে দেবে।

উদাহরণ স্বরূপ:

//index.js

store.dispatch(initScript());

ReactDOM.render(
  <Provider store={store}>
    <Routes />
  </Provider>,
  document.getElementById('root')
);

4
আমি একটি প্রতিক্রিয়া নবাগত, কিন্তু প্রতিক্রিয়া এবং রিডেক্স ধারণা সম্পর্কে প্রাথমিক ডকুমেন্টেশনগুলি পড়ার ভিত্তিতে, আমি বিশ্বাস করি এটি সবচেয়ে উপযুক্ত উপায়। কোনও componentDidMountইভেন্টে এই সূচনাটি তৈরি করার কোনও সুবিধা আছে কি?
কুজদিতোমি

4
এটা সত্যিই পরিস্থিতির উপর নির্ভর করে। সুতরাং componentDidMountনির্দিষ্ট উপাদান মাউন্ট করার আগে উইলটি ফায়ার করবে। store.dispatch()ReactDOM.reender () এর আগে ফায়ারিং the অ্যাপ্লিকেশনটি মাউন্ট হওয়ার আগেই আগুন লাগে। এটি componentWillMountসম্পূর্ণ অ্যাপ্লিকেশনের জন্য এক ধরণের । নবাগত হিসাবে, আমি মনে করি এটি উপাদান লাইফাইসাইক্যাল পদ্ধতিগুলি ব্যবহার করাতে আরও ভাল কারণ এটি যুক্তিটি যেখানে ব্যবহৃত হচ্ছে সেখানে দৃly়ভাবে মিলিয়ে রাখে। অ্যাপ্লিকেশনগুলি আরও জটিল হয়ে উঠলে এটি করা আরও শক্ত হয়ে যায়। আমার পরামর্শ হ'ল যতক্ষণ পারো তত সহজ রাখুন।
জোশ পিটম্যান

4
আমাকে উপরের পদ্ধতিরটি সম্প্রতি ব্যবহার করতে হয়েছিল। আমার একটি গুগল লগইন বোতাম ছিল এবং অ্যাপটি লোড হওয়ার আগে আমার এটির কাজ করতে একটি স্ক্রিপ্ট ফায়ার করা দরকার। আমি যদি অ্যাপটি লোড হওয়ার এবং তারপরে কল করার জন্য অপেক্ষা করে থাকি তবে প্রতিক্রিয়া পেতে অ্যাপ্লিকেশনটির কার্যকারিতা এবং বিলম্ব করতে আরও বেশি সময় লাগত। যদি একটি লাইফসাইকেলে জিনিসগুলি আপনার ব্যবহারের ক্ষেত্রে কাজ করে তবে লাইফেসাইকেলের সাথে লেগে থাকুন। তারা ভাবতে সহজ। এটি বিচার করার একটি ভাল উপায় হ'ল কোডটি এখন থেকে 6 মাস পরে দেখছেন picture অন্তর্নিহিতভাবে বুঝতে আপনার পক্ষে কোন পদ্ধতির পক্ষে আরও সহজ হবে। যে পদ্ধতির চয়ন করুন।
জোশ পিট্টম্যান

4
এছাড়াও, আপনাকে রিডেক্সএক্সের আপডেটটি সাবস্ক্রাইব করার দরকার নেই, কেবল প্রেরণের দরকার। এটিই এই পদ্ধতির পুরো বিষয়টি, আমি এই সিদ্ধান্তটি গ্রহণ করছি যে রিডুএক্স জিনিসটি (ডেটা আনার, কোনও ক্রিয়াকলাপ চালানো ইত্যাদি) ডিকুপল করে এবং ফলাফলটি (রেন্ডারিং, প্রতিক্রিয়া জানানো ইত্যাদি) ব্যবহার করে ou
জোশ পিটম্যান

4
আমি প্রেরণ সম্পর্কে আপনার বক্তব্য হ্যাঁ। রেডাক্স বলে না যে আমাদের একটি প্রতিক্রিয়া উপাদানটির ভিতরে থেকে ক্রিয়া প্রেরণ করতে হবে। রেডাক্স অবশ্যই প্রতিক্রিয়া থেকে স্বাধীন।
টুয়ানানহ্যাকওয়ার্স

18

আপনি যদি প্রতিক্রিয়া হুক ব্যবহার করছেন তবে একটি একক-লাইন সমাধান

useEffect(() => store.dispatch(handleAppInit()), []);

খালি অ্যারেটি নিশ্চিত করে যে এটি প্রথম রেন্ডারে একবার মাত্র বলা হয়েছিল।

সম্পূর্ণ উদাহরণ:

import React, { useEffect } from 'react';
import { Provider } from 'react-redux';

import AppInitActions from './store/actions/appInit';
import store from './store';

export default function App() {
  useEffect(() => store.dispatch(AppInitActions.handleAppInit()), []);
  return (
    <Provider store={store}>
      <div>
        Hello World
      </div>
    </Provider>
  );
}

11

2020 আপডেট : অন্যান্য সমাধানের পাশাপাশি আমি লগইন প্রচেষ্টা ব্যর্থ হওয়ার জন্য প্রতিটি অনুরোধ পরীক্ষা করতে রেডাক্স মিডলওয়্যারটি ব্যবহার করছি:

export default () => next => action => {
  const result = next(action);
  const { type, payload } = result;

  if (type.endsWith('Failure')) {
    if (payload.status === 401) {
      removeToken();

      window.location.replace('/login');
    }
  }

  return result;
};

আপডেট 2018 : এই উত্তরটির জন্য প্রতিক্রিয়া রাউটার 3 এর জন্য

আমি এন্টার প্রপস রিএ্যাক্ট -রাউটার ব্যবহার করে এই সমস্যাটি সমাধান করেছি । কোডটি দেখতে কেমন লাগে:

// this function is called only once, before application initially starts to render react-route and any of its related DOM elements
// it can be used to add init config settings to the application
function onAppInit(dispatch) {
  return (nextState, replace, callback) => {
    dispatch(performTokenRequest())
      .then(() => {
        // callback is like a "next" function, app initialization is stopped until it is called.
        callback();
      });
  };
}

const App = () => (
  <Provider store={store}>
    <IntlProvider locale={language} messages={messages}>
      <div>
        <Router history={history}>
          <Route path="/" component={MainLayout} onEnter={onAppInit(store.dispatch)}>
            <IndexRoute component={HomePage} />
            <Route path="about" component={AboutPage} />
          </Route>
        </Router>
      </div>
    </IntlProvider>
  </Provider>
);

11
কেবল পরিষ্কার হতে হবে প্রতিক্রিয়া-রাউটার 4 অন্টর সমর্থন করে না।
রব এল

ইন্টেলপ্রাইডারটি আরও ভাল সমাধানে আপনাকে একটি ইঙ্গিত দেবে .. নীচে আমার উত্তরটি দেখুন।
ক্রিস কেম্প

এটি পুরানো
রিঅ্যাক্ট

3

সঙ্গে redux-কাহিনী মিডলওয়্যার আপনি এটা চমত্কারভাবে কাজ করতে পারেন।

কেবলমাত্র একটি সাগা সংজ্ঞা দিন যা ট্রিগার হওয়ার আগে প্রেরণকারী ক্রিয়াকলাপের জন্য নজর রাখছে না (যেমন takeবা এর সাথে takeLatest)। যখন forkরুট কাহিনী থেকে ed মত এটি অ্যাপের স্টার্টআপে ঠিক একবার চালানো হবে।

নিম্নলিখিতটি একটি অসম্পূর্ণ উদাহরণ যা redux-sagaপ্যাকেজ সম্পর্কে কিছুটা জ্ঞানের প্রয়োজন তবে বিষয়টিটি ব্যাখ্যা করে:

সাগস / লঞ্চসাগা.জেএস

import { call, put } from 'redux-saga/effects';

import { launchStart, launchComplete } from '../actions/launch';
import { authenticationSuccess } from '../actions/authentication';
import { getAuthData } from '../utils/authentication';
// ... imports of other actions/functions etc..

/**
 * Place for initial configurations to run once when the app starts.
 */
const launchSaga = function* launchSaga() {
  yield put(launchStart());

  // Your authentication handling can go here.
  const authData = yield call(getAuthData, { params: ... });
  // ... some more authentication logic
  yield put(authenticationSuccess(authData));  // dispatch an action to notify the redux store of your authentication result

  yield put(launchComplete());
};

export default [launchSaga];

উপরের কোডটি একটি launchStartএবং প্রেরণ করেlaunchComplete তৈরি করা উচিত যা অ রিডাক্স ক্রিয়া করে। এ জাতীয় ক্রিয়াকলাপগুলি তৈরি করা একটি ভাল অনুশীলন, যখনই লঞ্চটি শুরু হয় বা সম্পন্ন হয় তখনই তারা রাষ্ট্রটিকে অন্য জিনিসগুলি করার বিষয়ে অবহিত করার কাজে আসে।

আপনার রুট সাগাটি এই launchSagaকাহিনীটি কাঁটাতে হবে:

sagas / index.js

import { fork, all } from 'redux-saga/effects';
import launchSaga from './launchSaga';
// ... other saga imports

// Single entry point to start all sagas at once
const root = function* rootSaga() {
  yield all([
    fork( ... )
    // ... other sagas
    fork(launchSaga)
  ]);
};

export default root;

এটি সম্পর্কে আরও তথ্যের জন্য দয়া করে রিডেক্স-সাগা এর সত্যিকারের ভাল ডকুমেন্টেশন পড়ুন ।


এই ক্রিয়াটি সঠিক না হওয়া পর্যন্ত পৃষ্ঠা লোড হবে না?
মার্কভ

2

প্রতিক্রিয়া (16.8) এর সর্বশেষ ব্যবহার করে এখানে একটি উত্তর দেওয়া হয়েছে:

import { appPreInit } from '../store/actions';
// app preInit is an action: const appPreInit = () => ({ type: APP_PRE_INIT })
import { useDispatch } from 'react-redux';
export default App() {
    const dispatch = useDispatch();
    // only change the dispatch effect when dispatch has changed, which should be never
    useEffect(() => dispatch(appPreInit()), [ dispatch ]);
    return (<div>---your app here---</div>);
}

অ্যাপ্লিকেশন অবশ্যই সরবরাহকারীর অধীনে থাকতে হবে। টাইপস্ক্রিপ্টকে সুখী করতে আমাকে প্রেরণের চারপাশে অতিরিক্ত বন্ধের বিজ্ঞাপন দিতে হয়েছিল: UseEffect (())>> {প্রেরণ (অ্যাপআইনিট ())}, [])।
PEZO

0

আমি অ্যাপ্লিকেশন টিআইপি-তে একটি এপিআই এন্ড-পয়েন্ট থেকে কোনও ব্যবহারকারীর অধীনে অ্যাকাউন্ট আনার জন্য রিডেক্স-থাঙ্ক ব্যবহার করছিলাম, এবং এটি অ্যাসিঙ্ক ছিল তাই আমার অ্যাপ্লিকেশনটি রেন্ডার করার পরে ডেটা আসছিল এবং উপরের বেশিরভাগ সমাধান আমার পক্ষে বিস্ময় প্রকাশ করেনি এবং কিছুগুলি হ'ল অবচয় সুতরাং আমি কম্পোনেন্টডিড আপডেট () এর দিকে চেয়েছিলাম। সুতরাং মূলত অ্যাপ্লিকেশন উদ্যোগে আমার এপিআই থেকে অ্যাকাউন্টের তালিকা থাকতে হয়েছিল এবং আমার রিডেক্স স্টোর অ্যাকাউন্টগুলি বাতিল বা [] হবে। এটির পরে আশ্রয় নেওয়া।

class SwitchAccount extends Component {

    constructor(props) {
        super(props);

        this.Format_Account_List = this.Format_Account_List.bind(this); //function to format list for html form drop down

        //Local state
        this.state = {
                formattedUserAccounts : [],  //Accounts list with html formatting for drop down
                selectedUserAccount: [] //selected account by user

        }

    }



    //Check if accounts has been updated by redux thunk and update state
    componentDidUpdate(prevProps) {

        if (prevProps.accounts !== this.props.accounts) {
            this.Format_Account_List(this.props.accounts);
        }
     }


     //take the JSON data and work with it :-)   
     Format_Account_List(json_data){

        let a_users_list = []; //create user array
        for(let i = 0; i < json_data.length; i++) {

            let data = JSON.parse(json_data[i]);
            let s_username = <option key={i} value={data.s_username}>{data.s_username}</option>;
            a_users_list.push(s_username); //object
        }

        this.setState({formattedUserAccounts: a_users_list}); //state for drop down list (html formatted)

    }

     changeAccount() {

         //do some account change checks here
      }

      render() {


        return (
             <Form >
                <Form.Group >
                    <Form.Control onChange={e => this.setState( {selectedUserAccount : e.target.value})} as="select">
                        {this.state.formattedUserAccounts}
                    </Form.Control>
                </Form.Group>
                <Button variant="info" size="lg" onClick={this.changeAccount} block>Select</Button>
            </Form>
          );


         }    
 }

 const mapStateToProps = state => ({
      accounts: state.accountSelection.accounts, //accounts from redux store
 });


  export default connect(mapStateToProps)(SwitchAccount);

0

আপনি যদি প্রতিক্রিয়া হুক ব্যবহার করছেন তবে আপনি সহজেই React.useEffect ব্যবহার করে একটি ক্রিয়া প্রেরণ করতে পারেন

React.useEffect(props.dispatchOnAuthListener, []);

আমি রেজিস্টার onAuthStateChangedশ্রোতার জন্য এই প্যাটার্নটি ব্যবহার করি

function App(props) {
  const [user, setUser] = React.useState(props.authUser);
  React.useEffect(() => setUser(props.authUser), [props.authUser]);
  React.useEffect(props.dispatchOnAuthListener, []);
  return <>{user.loading ? "Loading.." :"Hello! User"}<>;
}

const mapStateToProps = (state) => {
  return {
    authUser: state.authentication,
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    dispatchOnAuthListener: () => dispatch(registerOnAuthListener()),
  };
};

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

-1

ব্যবহার: অ্যাপোলো ক্লায়েন্ট 2.0, প্রতিক্রিয়া-রাউটার ভি 4, প্রতিক্রিয়া 16 (ফাইবার)

উত্তরটি নির্বাচিত পুরানো প্রতিক্রিয়া রাউটার v3 ব্যবহার করুন। অ্যাপটির জন্য গ্লোবাল সেটিংস লোড করতে আমার 'প্রেরণ' করা দরকার do কৌতুকটি উপাদানটি উইলআপডেট ব্যবহার করছে, যদিও উদাহরণটি অ্যাপোলো ক্লায়েন্ট ব্যবহার করছে এবং সমাধানগুলি সমান নয়। আপনার বাউকের দরকার নেই

SettingsLoad.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import {bindActionCreators} from "redux";
import {
  graphql,
  compose,
} from 'react-apollo';

import {appSettingsLoad} from './actions/appActions';
import defQls from './defQls';
import {resolvePathObj} from "./utils/helper";
class SettingsLoad extends Component {

  constructor(props) {
    super(props);
  }

  componentWillMount() { // this give infinite loop or no sense if componente will mount or not, because render is called a lot of times

  }

  //componentWillReceiveProps(newProps) { // this give infinite loop
  componentWillUpdate(newProps) {

    const newrecord = resolvePathObj(newProps, 'getOrgSettings.getOrgSettings.record');
    const oldrecord = resolvePathObj(this.props, 'getOrgSettings.getOrgSettings.record');
    if (newrecord === oldrecord) {
      // when oldrecord (undefined) !== newrecord (string), means ql is loaded, and this will happens
      //  one time, rest of time:
      //     oldrecord (undefined) == newrecord (undefined)  // nothing loaded
      //     oldrecord (string) == newrecord (string)   // ql loaded and present in props
      return false;
    }
    if (typeof newrecord ==='undefined') {
      return false;
    }
    // here will executed one time
    setTimeout(() => {
      this.props.appSettingsLoad( JSON.parse(this.props.getOrgSettings.getOrgSettings.record));
    }, 1000);

  }
  componentDidMount() {
    //console.log('did mount this props', this.props);

  }

  render() {
    const record = resolvePathObj(this.props, 'getOrgSettings.getOrgSettings.record');
    return record
      ? this.props.children
      : (<p>...</p>);
  }
}

const withGraphql = compose(

  graphql(defQls.loadTable, {
    name: 'loadTable',
    options: props => {
      const optionsValues = {  };
      optionsValues.fetchPolicy = 'network-only';
      return optionsValues ;
    },
  }),
)(SettingsLoad);


const mapStateToProps = (state, ownProps) => {
  return {
    myState: state,
  };
};

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators ({appSettingsLoad, dispatch }, dispatch );  // to set this.props.dispatch
};

const ComponentFull = connect(
  mapStateToProps ,
  mapDispatchToProps,
)(withGraphql);

export default ComponentFull;

App.js

class App extends Component<Props> {
  render() {

    return (
        <ApolloProvider client={client}>
          <Provider store={store} >
            <SettingsLoad>
              <BrowserRouter>
            <Switch>
              <LayoutContainer
                t={t}
                i18n={i18n}
                path="/myaccount"
                component={MyAccount}
                title="form.myAccount"
              />
              <LayoutContainer
                t={t}
                i18n={i18n}
                path="/dashboard"
                component={Dashboard}
                title="menu.dashboard"
              />

4
এই কোডটি অসম্পূর্ণ এবং প্রশ্নের অপ্রাসঙ্গিক অংশগুলির জন্য ছাঁটাই করা দরকার।
নাওস গোল্ডেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.