Best way to reorder a list realtime in React-Redux?

柔情痞子 提交于 2020-01-24 13:42:46

问题


I'm currently build an app that have a realtime list. the view of list as bellow picture:

This list will be updated realtime, when one of these actions is trigger:

  • A message is updated, the updated_time will be changed
  • Receive new message
  • Receive unread status of message

So I want to sort this list base on two conditions:

  1. All unRead_message allways at the top
  2. All message should be sorted by updated_time DESC (newest first), except unread_message always in prioty.

The data of this list is controled by these reduceres:

    export const data = createReducer(
    {},
    {
        [ CONVERSATIONS_RECEIVE ]: ( state, { conversations } ) => {
            return reduce(
                conversations,
                ( memo, conversation ) => {
                    const { id } = conversation.data;

                    if ( memo === state ) {
                        memo = { ...memo };
                    }

                    memo[ id ] = conversation;
                    return memo;
                },
                state
            );
        },
        [ RECEIVED_PENDING_MESSAGE ]: ( state, { data } ) => {

            if ( !data || !data.conversation_id in state ) return state;

            return update( state, {
                [ data.conversation_id ]: { data: { $merge: { snippet: data.message, updated_time: data.created_time } } }
            } )
        },
        [ RECEIVED_CONVERSATION_SEEN ]: ( state, { data } ) => {
            if ( !data || !data.conversation_id in state ) return state;

            return update( state, {
                [ data.conversation_id ]: { data: { $merge: { seen: true } } }
            } )
        },
        [ RECEIVED_CONVERSATION_UNSEEN ]: ( state, { data } ) => {
            if ( !data || !data.conversation || !data.conversation.id in state ) return state;

            return update( state, {
                [ data.conversation.id ]: { data: { $merge: { seen: false } } }
            } )
        },
    }
);

export function keys( state = [], action ) {
    switch ( action.type ) {
        case CONVERSATIONS_RECEIVE:
            if ( !action.conversations || !action.conversations.length ) return state;
            return state.concat( action.conversations.map( conversation => conversation.data.id ) );
        default:
    }

    return state;
}

export default combineReducers( {
    keys,
    data,
    isRequesting,
} );

The list data rendered by an array of keys:

[
  "id_1",
  "id_2",
  //....
]

and the data:

[
    {
        "data": {
            "can_comment": false,
            "can_hide": false,
            "can_like": false,
            "can_reply": true,
            "can_reply_privately": false,
            "comment_id": "",
            "id": "hbiocjgwxpncbnja8a3rra4oke",
            "is_hidden": false,
            "is_private": false,
            "last_seen_by": "ckj7mny56jrmir4df8h466uk7a",
            "message": "",
            "page_id": "1651651651651651",
            "post_id": "",
            "private_reply_conversation": "null",
            "scoped_thread_key": "t_1221211454699392",
            "seen": true,
            "snippet": "👑 [ TRI ÂN VÀNG-NGÀN ƯU ĐÃI ] 👑\nMiễn phí ship tận nhà 💛💛💛\nChỉ còn 350k trọn bộ COMBO 3 sản phẩm tuyệt vời cho chị em và các bé nhà mình : \n👉 Vòng tay chỉ đỏ kim vàng đính đá topaz được nhập từ Thái Lan \n👉 Dây chuyền hồ ly hợp mệnh \n👉 Vòng tay dâu tằm cho bé \nKhuyến mại chỉ áp dụng với những khách hàng đáng yêu nhận được tin nhắn này.Nhanh tay để lại SỐ ĐIỆN THOẠI để được thỉnh bộ sản phẩm với giá siêu khuyến mại này Chị  Chị Hai nha 💛💛💛",
            "type": "message",
            "unread_count": 0,
            "updated_time": "2018-12-07T12:00:21+0000"
        },
        "tags": [],
        "from": {
            "id": "1223645637789307",
            "name": "Chị Hai"
        }
    },
    {
        "data": {
            "can_comment": false,
            "can_hide": false,
            "can_like": false,
            "can_reply": true,
            "can_reply_privately": false,
            "comment_id": "",
            "id": "7oemjmkpxidi7cgk99ggbdamdw",
            "is_hidden": false,
            "is_private": false,
            "last_seen_by": "ckj7mny56jrmir4df8h466uk7a",
            "message": "",
            "page_id": "1651651651651651",
            "post_id": "",
            "private_reply_conversation": "null",
            "scoped_thread_key": "t_279998559200944",
            "seen": true,
            "snippet": "Giá hơi cao",
            "type": "message",
            "unread_count": 0,
            "updated_time": "2018-12-07T12:00:19+0000"
        },
        "tags": [],
        "from": {
            "id": "280004999200300",
            "name": "Chung Ngoc"
        }
    },
    // ..... other items
]

I have tried:

function mysortfunction(a, b) {

    // always sort by updated_time first
    if ( a.data.updated_time > b.data.updated_time ) return 1;
    if ( a.data.updated_time <= b.data.updated_time ) return -1;

    // if BOTH a.seen == false AND b.seen == false, we'll sort a & b by updated_time
    if ( !a.data.seen && !b.data.seen ) {
        if ( a.data.updated_time > b.data.updated_time ) return 1;
        if ( a.data.updated_time <= b.data.updated_time ) return -1;
    }

    return 0;
}

Can anyone tell me the best way to sort this list base on my conditions above, Thanks you very much!


回答1:


You can sort on multiple values in the following way:

const data = [
  { seen: true, updated_time: 'A' },
  { seen: true, updated_time: 'A' },
  { seen: false, updated_time: 'A' },
  { seen: false, updated_time: 'A' },
  { seen: false, updated_time: 'B' },
];
//compare booleans, returns -1,0 or 1
const compareSeen = (direction) => (a, b) =>
  a.seen === b.seen
    ? 0
    : a.seen
      ? -1 * direction
      : 1 * direction;
//compare strings, returns -1, 0 or 1
const compareDate = (direction) => (a, b) =>
  a.updated_time.localeCompare(b);

//pass array of compare functions and return a function that takes
//  a and b and keeps using compare functions until one of them returns non zero
const createSort = (comparers = []) => (a, b) =>
  comparers.reduce(
    (result, compareFn) =>
      result === 0 ? compareFn(a, b) : result,
    0,
  );
console.log(
  data
    .slice() //sort will mutate, we don't want that so we make a copy first
    .sort(createSort([compareSeen(-1), compareDate(1)])),
);

If you have ISO times from different timeZones you can not use string compare but have to map the date strings to numbers first and then map it back:

const data = [
  { seen: true, updated_time: '2018-12-07T12:00:21+0000' },
  { seen: true, updated_time: '2018-12-07T12:00:21+0000' },
  { seen: false, updated_time: '2018-12-07T12:00:21+0000' },
  { seen: false, updated_time: '2018-12-07T12:00:21+0000' },
  { seen: false, updated_time: '2018-12-07T12:00:21+0100' },
];
//compare booleans, returns -1,0 or 1
const compareSeen = (direction) => (a, b) =>
  a.seen === b.seen
    ? 0
    : a.seen
      ? -1 * direction
      : 1 * direction;
//compare numbers, returns negative number, 0 or positive number
const compareDate = (direction) => (a, b) =>
  (a.updated_time - b.updated_time) * direction;

//pass array of compare functions and return a function that takes
//  a and b and keeps using compare functions until one of them returns non zero
const createSort = (comparers = []) => (a, b) =>
  comparers.reduce(
    (result, compareFn) =>
      result === 0 ? compareFn(a, b) : result,
    0,
  );
console.log(
  data
    .map((item) => ({
      ...item,
      updated_time: new Date(item.updated_time).getTime(),
    })) //map already copied data so sort will not mutate it
    .sort(createSort([compareSeen(-1), compareDate(-1)]))
    .map((item) => ({
      ...item,
      updated_time: new Date(
        item.updated_time,
      ).toISOString(),//note: now you have strings in UTC/Zulu time
    })),
);



回答2:


I didn't read clearly all you code, but you can reorder your list only with javascript functions, you will use the sort() method to sort all your list by updated_time and seen or not_seen, you have to put a function to sort methode, but the only problem is that , the function passed to do the comparison need an int value as result, see their this link. so to do the trick, when doing the comparison, if his message is not seaan add to UPDATED_TIME +1000000000 for exemple.And like that all the unseen msg will be first, and all your message sort in with one function



来源:https://stackoverflow.com/questions/53757484/best-way-to-reorder-a-list-realtime-in-react-redux

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!