קורס React 2020 שיעור תרגול עבודה עם רשימות


זהו נושא דיון מלווה לערך המקורי שב־https://www.tocode.co.il/bundles/react/lessons/19-lab-lists

אפשר רמז? איך הכי נכון לארגן את הרשימה כדי לעשות את הsorting?

הי,

איך חשבת לגשת לזה?

אני הייתי שומר בסטייט את העמודה לפיה צריך למיין, ואז בתוך פונקציית הפקד מסתכל על המשתנה מהסטייט וממיין את המידע לפי ערך המשתנה

סבבה, עובד:):):slight_smile: רק עם באג קטן שאני לא מצליחה להבין… בפעם הראשונה שאני לוחצת על העמודה הsortField משום מה לא מתעדכן על הstate.
אח"כ אין שום בעיה והכל עובד פיקס…

האתר לא מאפשר לי להעלות לכאן את הקובץ…:frowning:

איזה כיף!
אפשר להדביק כאן קוד פשוט בתוך הודעה בלי בעיה למשל:

console.log('hello world!');

או לשים קישור ל codesandbox עם הפרויקט.

שימי את הקוד של הקומפוננטה שכתבת ואנסה לראות אם יש לי רעיון מה הבאג

תודה:)

הי @Sari.Elgabsi

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

המיון צריך להשפיע אך ורק על הקומפוננטה SortableTable.

בעצם מה שצריך לקרות זה שבתחילת הפונקציה מפעילים את המיון בכל מקרה לפי מפתח המיון שנמצא ב State. לחיצה על הכפתור רק משנה את מפתח המיון.

אני חושב על זה בתור משהו בסגנון הזה (זה לא קוד שעובד רק כדי להמחיש את הרעיון):

function SortableTable(props) {
  const { data } = props;
  const [sortKey, setSortKey] = useState(0);
  // sort(data, key) takes the data structure and the key,
  // and returns a new sorted data structure
  const dataToShow = sort(data, sortKey);

  // return creates a table from dataToShow  
  return (...);
}

איך בתוך בלוק הjsx הפנימי (של הth) אני יכול לגשת לאינדקס השורה?
רציתי לבדוק בפונ’ הטיפול באירוע אם האלמנט הוא מהשורה הראשונה ואם כן אז להפעילה.
ניסיתי לשלוח את row והוא לא יכל לגשת אליו (הופיע בדיבאגר כundefined)

    return (<div>

                <table>

                    {sortedData.map(row => (

                        <tr>

                            {

                                row.map(col => (

                                    <th onClick={e => handleClick(col, row)}>

                                        {col}

                                    </th>

                                ))

                            }

                        </tr>

                        ))}

                </table>

              </div>);

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

[10, 20, 30].map((val, index) => console.log(val, index))

הי ינון

יש לי פתרון עובד, אשמח להתייחסות לגבי אופן המימוש

import React, { useState } from 'react';

export default function Tablesort(props){

    const { data } = props;

    const tableHeader = data[0];

    const [tableSort, setTableSort] = useState(data[1]);

    const [tableData, setTableData] = useState(data.slice(2, data.length));

    function sortTable(col){

        const newTableData = [...tableData];

        const newTableSort = [...tableSort];

        if ( tableSort[col] === 'acs'){

            if ( typeof newTableData[0][col] === 'string'){

                newTableData.sort((a, b) => b[col] > a[col] ? 1: -1);

            } else {

                newTableData.sort((a, b) => b[col] - a[col]);   

            }      

        };

        if ( tableSort[col] === 'dec'){

            if ( typeof newTableData[0][col] === 'string'){

                newTableData.sort((a, b) => a[col] > b[col] ? 1: -1);

            } else {

                newTableData.sort((a, b) => a[col] - b[col]);   

            }         

        };

        { tableSort[col] === 'dec'? newTableSort[col] = 'acs': newTableSort[col] = 'dec'};

        setTableSort(newTableSort);

        setTableData(newTableData);  

    };

    return(

        <div>

            <table>

                <thead>

                    <tr>

                        {tableHeader.map((item, index) => (<th key={index} onClick={() => sortTable(index)}>{item}</th>))}

                    </tr>

                </thead>

                <tbody>

                    {tableData.map((item, i) => (

                    <tr key={i}>

                        {item.map((details, j) => (<td key={j}>{details}</td>))}

                    </tr>))}

                </tbody>

            </table>

        </div>

    );

}

הי שי,

נראה מעולה. הדבר היחיד שהייתי משנה זה הפונקציה הפנימית sortTable. יש בה המון לוגיקה וכשאתה רושם אותה כך בתוך קומפוננטה יהיה קשה להשתמש בלוגיקה הזאת במקומות נוספים בקוד. הייתי מציע לבנות פונקציה כללית יותר מחוץ לקומפוננטה שמקבלת את כל הפרמטרים שצריך (את כל משתני הסטייט) ומחזירה את המידע ממוין ומוכן להצגה. אני גם לא הייתי שומר את המידע הממוין בסטייט אלא רק את המידע הגולמי ופשוט מפעיל את הפונקציה שיצרתי כל פעם שמשנים את סדר המיון או העמודה

הי ינון

אני מבין את מה שאתה אומר, מבחינת ארכיטקטורה מראש בניתי פקד שיכול לקבל כל טבלא. להציג אותה ולמיין אותה

השאלה אם גם בפקד כזה, שמתוכנן לבצע פעולה ספציפית, כדאי להוציא את החלק הזה של הלוגיקה החוצה

לדעתי קוד פקד קצר זה משהו שהרבה יותר קל לקרוא ולתחזק, כלומר במקרה שלך קוד כזה:

import React, { useState } from 'react';

export default function Tablesort(props){

  const { data } = props;
  const [sortColumn, setSortColumn] = useState(0);
  const [sortOrder, setSortOrder] = useState(1); // 1 for ascending, -1 for descending
  const [tableHeader, tableData] = sortedTableData(data, sortColumn, sortDirection);

  return(
    <div>
      <table>
        <thead>
          <tr>
            {tableHeader.map((item, index) => (<th key={index} onClick={() => setSortColumn(index)}>{item}</th>))}
          </tr>
        </thead>

        <tbody>
          {tableData.map((item, i) => (
            <tr key={i}>
              {item.map((details, j) => (<td key={j}>{details}</td>))}
            </tr>))}
        </tbody>
      </table>
    </div>
  );
}

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

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

תודה על ההסבר, אני בהחלט מבין את הגישה

הי ינון

בהמשך ל custom hooks יצרתי קובץ utils.js

function useBuildTable (data) {

שמחזירה

return {tableHeader, tableData, sortTable};

ואז בפקד

import {useBuildTable} from '../practice-2/utils';

export default function Tablesort(props){
    const { data } = props;
    const table = useBuildTable(data);
    const tableHeader   = table.tableHeader;
    const tableData     = table.tableData;
    const sortTable     = table.sortTable;

ובפקד נשאר רק הרינדור

לייק 1

שלום ינון,
לא הצלחתי למיין את הטבלה בלי השורה הראשונה,

export default function SortAbleTable(props) {

const { dataTable } = props;

const [ newTableSort, setNewTableSort ] = useState([ ...dataTable ]);

const [count,setCount]=useState(0)

console.log(dataTable);

const headers = newTableSort[0];

function sortTable(index) {

    let table = [ ...dataTable ];

    table = table.sort((a, b) => (b[index] > a[index] ? 1 : -1));

    setNewTableSort(table);

    console.log(newTableSort);

    setCount(c=>c+1)

}

return (

    <div>

        <table key={count}>

            <thead>

                <tr >

                    {headers.map((head, index) => (

                        <th  onClick={() => sortTable(index)}>

                            {head}

                        </th>

                    ))}

                </tr>

            </thead>

            <tbody>

                {newTableSort.map(

                    (data, index) => index != 0 && <tr>{data.map((d, index) => <td >{d}</td>)}</tr>

                )}

            </tbody>

        </table>

    </div>

);

}

היי,
אשמח לכיוון כי ממש אין לי רעיון
זה מה שיש לי כרגע, אין לי שום רעיון איך לעשות את המיון בפועל? איך אני אדע אם זה סדר עולה או יורד? ואיך להימנע מלכתוב את הקוד פעמיים בביל עולה ובשביל יורד?

import React, { useState } from 'react';

export default function SortableTable(props){

    const { data } = props;

    const [ columnToSort, setColumnToSort ] = useState(0);

    const dataToShow = sort(data, columnToSort);

    function sort(data, columnToSort){

        const order = data[1][columnToSort] > data[2][columnToSort];

        

    }

    return (

        <>

            <table>

                <thead>

                    {

                        data[0].map((item, index) => (

                            <th onClick={ () => setColumnToSort(index) }>{item}</th>

                        ))

                    }

                </thead>

                <tbody>

                    {

                        dataToShow.map((item, index) => (     

                            <tr key={index}>

                                {

                                    dataToShow[index].map((item2, index2) => (

                                        <td>{item2}</td>

                                    ))

                                }

                            </tr>

                        )

                        )

                    }

                </tbody>

            </table>

        </>

    )

}

הי

נראה כיוון טוב. זאת הפונקציה למיון מערך ב JavaScript:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

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

בשביל מיון הפוך אפשר להוסיף קריאה ל:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse

זה מה שעשיתי אבל זה לא עובד לא יודעת למה
ואיך מדבגים את זה??

import React, { useState } from 'react';

export default function SortableTable(props){

    const { data } = props;

    const headers = data[0];

    data.shift();

    const [ columnToSort, setColumnToSort ] = useState(0);

    const dataToShow = sortTable( data, columnToSort);

    function sortTable(data, columnToSort){

        const order = data[0][columnToSort] > data[1][columnToSort];

        data.sort(function( a, b ){

            const firstValue = a[columnToSort];

            const secondValue = b[columnToSort];

            if ( firstValue < secondValue )

                if( !order ) return 1; else return -1;

            return 0;

        });

        return data;

    }

    return (

        <>

            <table>

                <thead>

                    {

                        headers.map((item, index) => (

                            <th onClick={ () => setColumnToSort(index)  }>{item}</th>

                        ))

                    }

                </thead>

                <tbody>

                    {

                        dataToShow.map((item, index) => (     

                            <tr key={index}>

                                {

                                    item.map((item2, index2) => (

                                        <td>{item2}</td>

                                    ))

                                }

                            </tr>

                        )

                        )

                    }

                </tbody>

            </table>

        </>

    )

}

יש הודעת שגיאה? מה בדיוק לא עובד? מה את רואה?