React Router Link with query params

02/06/2016

פוסט זה כולל טיפ קצר לעבודה עם React. אם אתם רוצים ללמוד איתי ריאקט מההתחלה ובצורה מקצועית תשמחו לשמוע שבניתי קורס מלא הכולל עשרות שיעורי וידאו והמון תרגול בו לומדים ריאקט מההתחלה ועד לנושאים המתקדמים.
לפרטים נוספים והרשמה בקרו בדף קורס ריאקט כאן באתר.
 

תוספת של פיצ'ר לאתר שברה לי חלק מהקישורים הפנימיים, והסימן המזהה של הנזק היה סימן שאלה שהופיע פעמיים ב URL. לא לקח הרבה זמן להבין שהאשמה בהתמודדות מוזרה של אלמנט Link של ריאקט-ראוטר עם נתיבים עם פרמטרים. כדי שאתם לא תיפלו באותו הבור, תוכלו למצוא כאן המחשה של הבעיה ואת המעקף שאני כתבתי.

1. מה שבור

אלמנט Link של react-router נועד לטפל בניווט פנימי באתר. אפשר להעביר לאלמנט זה נתיב יעד או נתיב ופרמטרים והוא כבר יבנה את שורת ה URL אוטומטית בשבילכם וגם יבצע ניתוב צד-לקוח בלבד.

השורות הבאות למשל עובדות מעולה:

<Link to="/home?theme=black">Home</Link>

<Link to={{pathname: "home", query: {theme: "black"}}} >Home</Link>

אבל אם תנסו לשלב פרמטרים ב pathname וגם ב query תקבלו קישור שבור:

{/* this produces the URL: /home?theme=black?name=bob */}
<Link to={{pathname: "/home?theme=black", query: {name: "bob"}}} >Home</Link>

הבעיה מתחילה כשה pathname מגיע במשתנה (שמקבל את ערכו למשל בצד השרת). במצב כזה לא תרצו להתחיל לבדוק כל פעם שאתם כותבים Link שהמשתנה לא מכיל סימני שאלה.

2. פתרון פשוט

לשם שינוי ולמרות חוסר חיבתי ל react-router, הפעם אני לא חושב שזה באשמתם. הם הגדירו ממשק לספריה שלהם וחבל לפגוע לכולם בביצועים רק בשביל לבדוק שאין סימני שאלה במשתנה pathname. לגיטימי לדרוש מהמתכנתים שמשתמשים בספריה שלכם לסדר את המשתנים שלהם לפני שיוצרים Link.

מצד שני אנחנו גם לא רוצים להריץ קוד לסידור המשתנים בכל מקום ש pathname מועבר כמשתנה, כי זה מועד לטעויות וכפילות קוד.

הפתרון הפשוט אם כן הוא לייצר אלמנט Link חדש שיעטוף את ה Link של react-router ויוסיף את היכולת שאני צריך, כלומר ישבור את הפרמטרים מ pathname. הנה הקוד:

/**
* Wrapping React-Router's Link to allow query parameters in pathname
 */

import React from 'react';
import { Link } from 'react-router';
import qs from 'query-string';

export default function MyLink(props) {
  try {
    const dest = props.to;
    if (typeof dest === 'object') {
      const path = dest.pathname;

      if (path.indexOf('?') >= 0) {
        // found query params in path- move it to query
        const queryParams = qs.parse(qs.extract(path));
        dest.pathname = path.substr(0, path.indexOf('?'));
        dest.query = Object.assign({}, dest.query, queryParams);
      }
    }
  } catch (err) {
    console.log(err);
  }

  return <Link {...props} >{props.children}</Link>;
}

גם במקרה הכללי, הדרך המומלצת לתקן בעיות בספריות ריאקט היא לעטוף אותן באלמנטים שלכם. מקומות שצריכים את שבירת הפרמטרים ישתמשו ב Link המיוחד שלנו, ואילו במקומות שאנו יודעים שה pathname לא יכיל סימני שאלה נעדיף את ה Link הפשוט של react-router.