شرح HTTP Requests باستخدام fetch في React Native

عبدالهاديمنذ سنتين

 

 

بسم الله الرحمن الرحيم
السلام عليكم ورحمة الله وبركاته

أهلا و سهلا بكم اخواني الأعزاء، في هذه المقالة سنتطرق الى استخدام fetch لمعالجة طلبات الشبكة (Handling Network Requests) في مكتبة React Native، اذا كنت جديداً معنا أنصحك بالعودة الى دروس سابقة لنمشي بخطوات مبسطة لنكمل المسيرة مع بعض و تكون فاهماً لهذه المقالة بحول الله. 

عند انشائك لأي تطبيق على الانترنت، غالباً ما تحتاج الى استخدام طلبات تتصل بالانترنت لتجلب محتوى أو نتيجة معينة أو تسجيل معلومات مَا على قاعدة بياناتك، أو على الأقل ربطه بتقنية firebase أو الفيسبوك لعمليات تسجيل الدخول و الخروج.

و خاصية الاتصال بالنت من خلال تطبيقك لعلها تتطلب منك معرفة و لو قليلة بعمليات (HTTP Request) لتكون الأمور واضحة للغاية بعد قليل ان شاء الله. من المعروف أن كل لغات البرمجة توفر هذه العمليات و تنظمها تحت مكتبات معينة و مختلفة، كذلك الجافاسكربت، و حتى React Native لديها مكتبات تفوق 100 مكتبة متخصصة فقط بهذه التطبيقات العمليات (منها axios و هي الشهيرة و المستحسنة).

في مكتبة الرياكت نيتف، توفر لديها شيئا مضمناً يدعى بـ Fetch API تقنية جديدة و مطورة و محسّنة أيضا من ذي قبل على XMLHttpRequest، و لكن Fetch الجديدة توفر مجموعة ميزة أكثر قوة ومرونة. 

بداية قبل انشائنا لأي طلب علينا تحديد شيئين مهمين هما: 

  1. الرابط الذي نجلب منه ما نحتاج يدعى بـ (URL) 
  2. تحديد الأسلوب الذي سنتصل به لهذا الرابط (Request Method)

تقديم الطلب (Making requests)

من أجل جلب المحتوى من URL الخاص بك ما عليك تمريره من خلال Fetch كالآتي: 


fetch('https://mywebsite.com/mydata.json');

تأخذ Fetch أيضا وسيط ثاني اختياري يسمح لك بتخصيص طلبك. قد ترغب في تحديد headers المرسل تقديم طلب POST معيّن:


fetch('https://mywebsite.com/endpoint/', {
  method: 'POST',
  headers: {
    Accept: 'application/json',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstParam: 'yourValue',
    secondParam: 'yourOtherValue',
  }),
});

هناك تفاصيل أكبر من ذلك لكن لا نحتاجها في تطبيقنا هذا - يمكنك مراجعة المرع الخاص بهذه الدالة على الرابط (Fetch Request docs) .

 

التعامل مع الاستجابة (Handling the response)

عند تقديمك للعديد من الطلبات، سوف تحتاج طبعاً إلى القيام بشيء مع الاستجابة، سنستعمل مثالا من الفيسبوك (Docs) نحاول فيه تخزين المعلومات الآتية و ربطه بمتغير التخزين (movies) : 


function getMoviesFromApiAsync() {
  return fetch('https://facebook.github.io/react-native/movies.json')
    .then((response) => response.json())
    .then((responseJson) => {
      return responseJson.movies;
    })
    .catch((error) => {
      console.error(error);
    });
}

هذا هو الأسلوب الذي تجده كثيراً في الانترنت لكن ظهر نوع آخر (ES2017) - يدعى بـ (async/await) تم شرحه في عالم البرمجة سابقاً مع Nodejs .. 


async function getMoviesFromApi() {
  try {
    let response = await fetch(
      'https://facebook.github.io/react-native/movies.json'
    );
    let responseJson = await response.json();
    return responseJson.movies;
  } catch (error) {
    console.error(error);
  }
}

لنستخدم الآن مثالا مباشراً مع (ListView) و (ActivityIndicator = عبارة عن أيقونة التحميل Loading


import React, { Component } from 'react';
import { ActivityIndicator, ListView, Text, View } from 'react-native';

export default class Movies extends Component {
  constructor(props) {
    super(props);
    this.state = {
      isLoading: true
    }
  }

  componentDidMount() {
    return fetch('https://facebook.github.io/react-native/movies.json')
      .then((response) => response.json())
      .then((responseJson) => {
        let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.setState({
          isLoading: false,
          dataSource: ds.cloneWithRows(responseJson.movies),
        }, function() {
          // do something with new state
        });
      })
      .catch((error) => {
        console.error(error);
      });
  }

  render() {
    if (this.state.isLoading) {
      return (
        <View style={{flex: 1, paddingTop: 20}}>
          <ActivityIndicator />
        </View>
      );
    }

    return (
      <View style={{flex: 1, paddingTop: 20}}>
        <ListView
          dataSource={this.state.dataSource}
          renderRow={(rowData) => <Text>{rowData.title}, {rowData.releaseYear}</Text>}
        />
      </View>
    );
  }
}

لنشرح ما كتبنا سابقاً و نوضح الأمور خطوة بخطوة: 

  • (دورة الحياة) componentDidMount : دائما عندما نودّ جلب استدعاءات معينة نستخدم هذه الوظيفة، لانها تعمل قبل أن يتم تنفيذ Rendering و بداخلها دالة Fetch تقوم باستدعاء المحتوى الموجود بالرابط الخاص بالمثال كصيغة Json و تستدعيه و تنظر: هل فعلاً هناك محتوى .. اذا كانت بنعم ستجلب النتيجة و تحتفظ بها في ListView مباشرة .. 
  • isLoading : أنشأنا لها حالة (State) تتغير قيمتها بخطأ (False) أو صحيح (True) لنجعلها تظهر قبل أن يتم جلب المحتوى و تختفي بعده مباشرة عند ظهور النتيجة .. و نغير القيمة كما شرحنا سابقاً عبر دالة setState .. 
  • .catch : عبارة عن لاقط للأخطاء في حالة حدوث مشكل أو توقف للموقع .. الخ و هو افتراضي و ضروري! 

نتيجة التطبيق على الأيباد الخاص بي باستخدام تطبيق Expo (يمكن لأي أحد تجربته)

5a92b710d417a_photo5805652241015745819(1).thumb.jpg.ee3d4673a3da53ac9698166809b16ff2.jpg

 

معلومة مهمة:

في أنظمة iOS لكي يعمل رابط يجب أن يكون يقترن بـ SSL حتى يعمل بشكل عادي مع (https) - أو تذهب لملف xcode المرفق مع مشروعك و تضيف له استثناءاً في (App Transport Security exception)

مكتبات أخرى: 

  • هناك مكتبة ذكرناها سلفاً هي الأخرى مدعومة في مكتبة رياكت نيتف - (XMLHttpRequest API) - و لا ينصح باستخدامها -  مثال:

var request = new XMLHttpRequest();
request.onreadystatechange = (e) => {
  if (request.readyState !== 4) {
    return;
  }

  if (request.status === 200) {
    console.log('success', request.responseText);
  } else {
    console.warn('error');
  }
};

request.open('GET', 'https://mywebsite.com/endpoint/');
request.send();

 

  • WebSocket : مدعومة هي الأخرى مع الرياكت نيتف، هو بروتوكول مزدوج (full-duplex) يتصل عبر قنوات (TCP connection) - مثال: 

var ws = new WebSocket('ws://host.com/path');

ws.onopen = () => {
  // connection opened
  ws.send('something'); // send a message
};

ws.onmessage = (e) => {
  // a message was received
  console.log(e.data);
};

ws.onerror = (e) => {
  // an error occurred
  console.log(e.message);
};

ws.onclose = (e) => {
  // connection closed
  console.log(e.code, e.reason);
};

 

  • هناك أيضاً (axios) التي أتسخدمها دائما - و (frisbee)  ..

 

نصل الى نهاية درس اليوم، أي استفسار أو جملة مبهمة لا يردكم الكيبورد نحن متواجون باذن الله للرد على استفساراتكم. دعواتكم لنا. 

 

 

 

1
إعجاب
1720
مشاهدات
0
مشاركة
2
متابع

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !