खोज…


परिचय

Ngrx एक शक्तिशाली पुस्तकालय है जिसका उपयोग आप Angular2 के साथ कर सकते हैं। इसके पीछे का विचार दो अवधारणाओं को मिलाना है जो एक पूर्वानुमानित राज्य कंटेनर के साथ एक प्रतिक्रियाशील ऐप को एक साथ चलाने के लिए अच्छा है: - [Redux] [1] - [RxJs] [२] मुख्य लाभ: - अपने घटकों के बीच अपने ऐप में डेटा साझा करना आसान हो रहा है - अपने ऐप कोर लॉजिक का परीक्षण करना, शुद्ध कार्यों का परीक्षण करना है, बिना किसी निर्भरता के Angular2 (बहुत आसान है!) [1]: http://redux.js.org [2]: http: // reactivex। कब / rxjs

पूरा उदाहरण: एक उपयोगकर्ता लॉगिन / लॉगआउट करें

आवश्यक शर्तें

यह विषय Redux और / या Ngrx के बारे में नहीं है :

  • आपको Redux के साथ सहज होने की आवश्यकता है
  • कम से कम RxJs और ऑब्जर्वेबल पैटर्न की मूल बातें समझें

सबसे पहले, आइए एक उदाहरण को शुरू से ही परिभाषित करें और कुछ कोड के साथ खेलें:

एक डेवलपर के रूप में, मैं चाहता हूं:

  1. एक IUser इंटरफ़ेस है जो User के गुणों को परिभाषित करता है
  2. उन क्रियाओं को घोषित करें जिनका उपयोग हम बाद में User को Store में हेरफेर करने के लिए करेंगे
  3. UserReducer की प्रारंभिक स्थिति को परिभाषित करें
  4. Reducer UserReducer बनाएँ
  5. Store बनाने के लिए हमारे UserReducer को हमारे मुख्य मॉड्यूल में आयात करें
  6. हमारे विचार में जानकारी प्रदर्शित करने के लिए Store डेटा का उपयोग करें

स्पॉइलर अलर्ट : यदि आप डेमो को तुरंत आज़माना चाहते हैं या कोड शुरू करने से पहले, यहां तक कि हम यहां शुरू कर सकते हैं, एक प्लंकर ( व्यू या रन व्यू देखें )।

1) IUser इंटरफ़ेस को परिभाषित करें

मुझे अपने इंटरफेस को दो भागों में विभाजित करना पसंद है:

  • वे गुण जो हम सर्वर से प्राप्त करेंगे
  • गुण जो हम केवल UI के लिए निर्धारित करते हैं (उदाहरण के लिए एक बटन कताई होना चाहिए)

और यहाँ IUser का इंटरफ़ेस हम उपयोग करेंगे:

user.interface.ts

export interface IUser {
  // from server
  username: string;
  email: string;
  
  // for UI
  isConnecting: boolean;
  isConnected: boolean;
};

2) User को हेरफेर करने के लिए कार्रवाई की घोषणा करें

अब हमें यह सोचने को मिला है कि हमारे रिड्यूसर को किस तरह की कार्रवाइयों को संभालना है।
यहाँ कहते हैं:

user.actions.ts

export const UserActions = {
  // when the user clicks on login button, before we launch the HTTP request
  // this will allow us to disable the login button during the request
  USR_IS_CONNECTING: 'USR_IS_CONNECTING',
  // this allows us to save the username and email of the user
  // we assume those data were fetched in the previous request
  USR_IS_CONNECTED: 'USR_IS_CONNECTED',

  // same pattern for disconnecting the user
  USR_IS_DISCONNECTING: 'USR_IS_DISCONNECTING',
  USR_IS_DISCONNECTED: 'USR_IS_DISCONNECTED'
};

लेकिन इससे पहले कि हम उन कार्यों का उपयोग करें, मुझे समझाएं कि हमें उन कार्यों में से कुछ को भेजने के लिए एक सेवा की आवश्यकता क्यों है:

मान लीजिए कि हम एक उपयोगकर्ता को कनेक्ट करना चाहते हैं। तो हम एक लॉगिन बटन पर क्लिक करेंगे और यहाँ पर क्या होने वाला है:

  • बटन पर क्लिक करें
  • घटक ईवेंट को userService.login और userService.login कॉल userService.login
  • userService.login विधि dispatch एक घटना हमारे स्टोर संपत्ति अद्यतन करने के लिए: user.isConnecting
  • एक HTTP कॉल निकाल दी जाती है (हम async व्यवहार का अनुकरण करने के लिए डेमो में setTimeout उपयोग करेंगे)
  • एक बार HTTP कॉल समाप्त होने के बाद, हम अपने स्टोर को चेतावनी देने के लिए एक और कार्रवाई भेजेंगे कि एक उपयोगकर्ता लॉग इन है

user.service.ts

@Injectable()
export class UserService {
  constructor(public store$: Store<AppState>) { }

  login(username: string) {
    // first, dispatch an action saying that the user's tyring to connect
    // so we can lock the button until the HTTP request finish
    this.store$.dispatch({ type: UserActions.USR_IS_CONNECTING });

    // simulate some delay like we would have with an HTTP request
    // by using a timeout
    setTimeout(() => {
      // some email (or data) that you'd have get as HTTP response
      let email = `${username}@email.com`;

      this.store$.dispatch({ type: UserActions.USR_IS_CONNECTED, payload: { username, email } });
    }, 2000);
  }

  logout() {
    // first, dispatch an action saying that the user's tyring to connect
    // so we can lock the button until the HTTP request finish
    this.store$.dispatch({ type: UserActions.USR_IS_DISCONNECTING });

    // simulate some delay like we would have with an HTTP request
    // by using a timeout
    setTimeout(() => {
      this.store$.dispatch({ type: UserActions.USR_IS_DISCONNECTED });
    }, 2000);
  }
}

3) UserReducer की प्रारंभिक स्थिति को परिभाषित करें

user.state.ts

export const UserFactory: IUser = () => {
  return {
    // from server
    username: null,
    email: null,

    // for UI
    isConnecting: false,
    isConnected: false,
    isDisconnecting: false
  };
};

4) Reducer UserReducer बनाएँ

एक Reducer 2 तर्क लेता है:

  • वर्तमान राज्य
  • टाइप Action का एक Action Action<{type: string, payload: any}>

अनुस्मारक: कुछ बिंदु पर एक reducer को आरंभ करने की आवश्यकता है

जैसा कि हमने भाग 3 में अपने रिड्यूसर की डिफ़ॉल्ट स्थिति को परिभाषित किया है), हम इसका उपयोग करने में सक्षम होंगे:

user.reducer.ts

export const UserReducer: ActionReducer<IUser> = (user: IUser, action: Action) => {
  if (user === null) {
    return userFactory();
  }
  
  // ...
}

उम्मीद है, यह लिखने का एक आसान तरीका है कि किसी वस्तु को वापस करने के लिए हमारे factory फ़ंक्शन का उपयोग करके और reducer के भीतर एक (ES6) डिफ़ॉल्ट पैरामीटर मान का उपयोग करें :

export const UserReducer: ActionReducer<IUser> = (user: IUser = UserFactory(), action: Action) => {
  // ...
}

फिर, हमें अपने reducer में हर क्रिया को संभालने की आवश्यकता है: TIP : हमारे राज्य को अपरिवर्तनीय रखने के लिए ES6 Object.assign फ़ंक्शन का उपयोग करें

export const UserReducer: ActionReducer<IUser> = (user: IUser = UserFactory(), action: Action) => {
  switch (action.type) {
    case UserActions.USR_IS_CONNECTING:
      return Object.assign({}, user, { isConnecting: true });

    case UserActions.USR_IS_CONNECTED:
      return Object.assign({}, user, { isConnecting: false, isConnected: true, username: action.payload.username });

    case UserActions.USR_IS_DISCONNECTING:
      return Object.assign({}, user, { isDisconnecting: true });

    case UserActions.USR_IS_DISCONNECTED:
      return Object.assign({}, user, { isDisconnecting: false, isConnected: false });

    default:
      return user;
  }
};

5) Store बनाने के लिए हमारे UserReducer को हमारे मुख्य मॉड्यूल में आयात करें

app.module.ts

@NgModule({
    declarations: [
    AppComponent
    ],
    imports: [
    // angular modules
    // ...

    // declare your store by providing your reducers
    // (every reducer should return a default state)
    StoreModule.provideStore({
        user: UserReducer,
        // of course, you can put as many reducers here as you want
        // ...
    }),

    // other modules to import
    // ...
    ]
});

6) हमारे विचार में जानकारी प्रदर्शित करने के लिए Store डेटा का उपयोग करें

सब कुछ अब तर्क की तरफ से तैयार है और हमें बस यह प्रदर्शित करना है कि हम दो घटकों में क्या चाहते हैं:

  • UserComponent : [डंब कंपोनेंट] हम @Input प्रॉपर्टी और async पाइप का उपयोग करके यूजर ऑब्जेक्ट को स्टोर से पास करेंगे। इस तरह, घटक केवल उपलब्ध होने पर user को user करेगा (और user प्रकार IUser और प्रकार का नहीं Observable<IUser> !)
  • LoginComponent [स्मार्ट घटक] हम सीधे Store को इस घटक में इंजेक्ट करेंगे और केवल एक Observable रूप में user पर काम करेंगे।

user.component.ts

@Component({
  selector: 'user',
  styles: [
    '.table { max-width: 250px; }',
    '.truthy { color: green; font-weight: bold; }',
    '.falsy { color: red; }'
  ],
  template: `
    <h2>User information :</h2>

    <table class="table">
      <tr>
        <th>Property</th>
        <th>Value</th>
      </tr>

      <tr>
        <td>username</td>
        <td [class.truthy]="user.username" [class.falsy]="!user.username">
          {{ user.username ? user.username : 'null' }}
        </td>
      </tr>

      <tr>
        <td>email</td>
        <td [class.truthy]="user.email" [class.falsy]="!user.email">
          {{ user.email ? user.email : 'null' }}
        </td>
      </tr>

      <tr>
        <td>isConnecting</td>
        <td [class.truthy]="user.isConnecting" [class.falsy]="!user.isConnecting">
          {{ user.isConnecting }}
        </td>
      </tr>

      <tr>
        <td>isConnected</td>
        <td [class.truthy]="user.isConnected" [class.falsy]="!user.isConnected">
          {{ user.isConnected }}
        </td>
      </tr>

      <tr>
        <td>isDisconnecting</td>
        <td [class.truthy]="user.isDisconnecting" [class.falsy]="!user.isDisconnecting">
          {{ user.isDisconnecting }}
        </td>
      </tr>
    </table>
  `
})
export class UserComponent {
  @Input() user;

  constructor() { }
}

login.component.ts

@Component({
  selector: 'login',
  template: `
    <form
      *ngIf="!(user | async).isConnected"
      #loginForm="ngForm"
      (ngSubmit)="login(loginForm.value.username)"
    >
      <input
        type="text"
        name="username"
        placeholder="Username"
        [disabled]="(user | async).isConnecting"
        ngModel
      >
 
      <button
        type="submit"
        [disabled]="(user | async).isConnecting || (user | async).isConnected"
      >Log me in</button>
    </form>
 
    <button
      *ngIf="(user | async).isConnected"
      (click)="logout()"
      [disabled]="(user | async).isDisconnecting"
    >Log me out</button>
  `
})
export class LoginComponent {
  public user: Observable<IUser>;
 
  constructor(public store$: Store<AppState>, private userService: UserService) {
      this.user = store$.select('user');
  }
 
  login(username: string) {
    this.userService.login(username);
  }
 
  logout() {
    this.userService.logout();
  }
}

चूंकि Ngrx Redux और RxJs अवधारणाओं का एक मर्ज है, इसलिए Ngrx में Ngrx को एक RxJs समझना काफी कठिन हो सकता है। लेकिन यह एक शक्तिशाली पैटर्न है जो आपको अनुमति देता है जैसा कि हमने इस उदाहरण में देखा है कि एक प्रतिक्रियाशील ऐप है और क्या आप आसानी से अपना डेटा साझा कर सकते हैं। यह मत भूलो कि वहाँ एक प्लंकर उपलब्ध है और आप इसे अपने खुद के परीक्षण बनाने के लिए कांटा कर सकते हैं!

मुझे आशा है कि यह मददगार था यहां तक कि विषय काफी लंबा है, चीयर्स!



Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow