0

My redux store updates perfectly

after sorting

before sorting

But the props in my component don't update even when the store has updated and so the child components still show the old values. I'm sorting my channels according to the timestamp. The sorting function updates the redux store but it still renders the non-sorted data.

the output it should be sorted but it remains the same(unsorted)

This is my component code

    export const RoomItem = (props) => {
    const [roomLiveStatus, setRoomLiveStatus] = useState(false);

    const compareTimestamp = (t1 = 0, t2 = 0) => {
        return (t1.lastMessage && t2.lastMessage) && t2.lastMessage.timestamp - t1.lastMessage.timestamp
    }

    const getRoomData = () => {

        const { roomData, workspace } = props;

        const { workspaceId } = workspace
        const workspaceIdLowerCase = workspaceId.toLowerCase()

        const { roomId } = roomData;
        const roomIdLowerCase = roomId.toLowerCase()
        firebase
            .firestore()
            .collection(`sessions/${workspaceIdLowerCase}/rooms`)
            .doc(`${roomIdLowerCase}`)
            .onSnapshot(doc => {
                if (doc.exists) {
                    // console.log("LIVE Sessions doc: ", doc.data())
                    const { currentSession } = doc.data()
                    if (currentSession !== "") {
                        setRoomLiveStatus(true)
                    } else {
                        setRoomLiveStatus(false)
                    }
                }
            })
    }

    useEffect(() => {
        getRoomData();
    },[])


    useEffect(() => {
        // do something
        getRoomData();
        // console.log(props,"props of roomitem")
    },[props.sortType])


    const strip = (value) => {

        const { user, content } = value
        let name = user.name;
        let firstName = name.trim().split(" ")[0]

        if (value.type === 0) {
            if ( (firstName.length + content.length) > 32 ) {
                let completeContent = `${firstName}: ${content}`
                return `${completeContent.slice(0, 32)}...`

            } else {
                return `${firstName}: ${content}`                
            }

        } else if (value.type === 1) {
            return <span>{firstName}: <FontAwesomeIcon icon={faCalendarAlt} className="text-theme" /> Schedule</span>

        } else if (value.type === 2) {
            return (
                <span>{firstName}: <FontAwesomeIcon icon={faClipboard} className="text-theme" />Files</span>
            );
        } else if (value.type === 3) {
            return <span>{firstName}: <FontAwesomeIcon icon={faPoll} className="text-theme" /> Poll</span>

        } else if (value.type === 4) {
            return <span>{firstName}: <FontAwesomeIcon icon={faTasks} className="text-theme" /> Quiz</span>

        } else if (value.type === 6) {
            if ( (firstName.length + content.length) > 32) {
                let len = 32 - firstName.length;
                
                return <span>{firstName}: <FontAwesomeIcon icon={faImage} /> {content.length > len ? content.slice(0, len) + '…' : content}</span>
            } else {
                return <span>{firstName}: <FontAwesomeIcon icon={faImage} /> Photo</span>
            }

        } else if (value.type === 7) {
            if ( (firstName.length + content.length) > 32) {
                let len = 32 - firstName.length;
                
                return <span>{firstName}: <FileIcon message={value} /> {content.length > len ? content.slice(0, len) + '…' : content}</span>
            } else {
                return <span>{firstName}: <FileIcon message={value} /> {value.metaData && value.metaData.name}</span>
            }

        } else if (value.type === 8) {
            return <span>{content.length > 36 ? `${content.slice(0, 36)}...` : content}</span>

        } else if (value.type === 9) {
            return <span>{content.length > 36 ? `${content.slice(0, 36)}...` : content}</span>
            
        } else {
            return value.type

        }
    }

    const {
        key,
        currentChannel,
        workspaceData,
        workspace,

        setCurrentChannel,
        setCurrentWorkspace,
        setParticipants,
        resetData
    } = props;
    const roomData = props.roomData;
    const { roomId } = roomData;


    return( 
            <li
                className={currentChannel && (roomData.roomId === currentChannel.roomId)
                    ? "active rounded-lg py-1 m-1 bg-card-theme shadow-sm text-theme"
                    : "rounded-lg py-1 m-1 bg-card-theme shadow-sm text-theme"}
                key={key}
                onClick={() => {
                    setCurrentChannel({ ...roomData, roomId })
                    setCurrentWorkspace({ ...workspaceData, ...workspace })
                    setParticipants(workspace.workspaceId, roomId)
                    resetData()
                    // setLeftPanel(!this.props.displayLeftPanel);
                }}
                name={roomData.roomName}
                active={currentChannel && (roomData.roomId === currentChannel.roomId)}
            >
                <div className="d-flex align-items-center p-2 w-100">
                    <div className={roomLiveStatus ? "liveroom" : ""}>
                        <img
                            className={roomLiveStatus ? "mr-2 rounded-circle profile-image" : "mr-2 rounded-circle"}
                            src={roomData.roomPic}
                            style={{ height: 45, width: 45 }} />
                    </div>
                    <div className="flex-grow-1">
                        <div className="d-flex align-items-center">
                            {(roomData.roomType === 1)
                                && <FontAwesomeIcon
                                    icon={faLock}
                                    className="text-success mr-2"
                                    size="xs" />}
                            <p className="mb-0 text-theme">{roomData.roomName}</p>
                        </div>
                        {roomData.lastMessage
                            && <small className="text-theme text-theme-lighter">
                                <span>{strip(roomData.lastMessage)}</span>
                            </small>}
                    </div>
                    <div className="text-right align-self-start">
                        {/* <FontAwesomeIcon
                            icon={faThumbtack}
                            style={isPinned ? { fontSize: 12, transform: "rotate(45deg)" } : { fontSize: 12 }}
                            className={isPinned ? "text-theme" : "text-secondary"} /> */}
                        <p
                            className="mb-0 text-theme small text-theme-lighter"
                            style={{ whiteSpace: "nowrap" }}
                        >
                            {roomData.lastMessage 
                                && timeFromNow(roomData.lastMessage.timestamp)}
                        </p>
                        {/* Messages Notification */}
                        {/* <span className="text-white bg-primary smaller font-weight-bold" style={{ whiteSpace: "nowrap", borderRadius: "2px", padding: "3px 3px 3px 3px" }}>
                            99+</span> */}
                    </div>
                </div>
            </li>
    )
}

const WorkspaceListElement = (props) => {

    const [workspaceData, setWorkspaceData] = useState({});
    const [loadingWorkspaceData, setLoadingWorkspaceData] = useState(true);
    const [roomsDataArray, setRoomsDataArray] = useState([]);
    const [sortingCount, setSortingCount] = useState(0);


    const getWorkspaceData = async () => {
        const { workspace } = props;

        let docRef = await firebase.firestore().collection(`workspaces`).doc(`${workspace.workspaceId}`)
        let workspace_data = await docRef.get()
            .then(function (doc) {
                if (doc.exists) {
                    // console.log("Document data workspace:", doc.data());
                    const workspaceData = doc.data()
                    return workspaceData;
                } else {
                    // doc.data() will be undefined in this case
                    console.log("No such document!");
                }
            })
            .catch(function (error) {
                console.log("Error getting document:", error);
            })

        setWorkspaceData(workspace_data);
        setLoadingWorkspaceData(false);
    }



    const getAllRoomsData = () => {

        const { workspace, roomsVisible, setChannels } = props
        let roomsArray = []
        let roomsDataPromises = []
        let roomsDataArray = []

        getWorkspaceData()

        roomsArray = workspace[roomsVisible] && Object.values(workspace[roomsVisible]).map((room, key) => (
            room.roomId
        ))

        // console.log(`roomsArray ${JSON.stringify(roomsArray)}`)

        roomsDataPromises = roomsArray.map((roomId, key) => firebase.firestore().collection(`workspaces/${workspace.workspaceId}/rooms`).doc(`${roomId}`).get())

        Promise.all(roomsDataPromises).then(values => {
            roomsDataArray = values.map(value => {
                return { ...value.data(), roomId: value.id }
            })
            setChannels(roomsDataArray)
        })
    }

    const {
        workspace,
        _handleAddRoom,
        _handleOpenWorkspaceDetails,
        roomsVisible,
        currentChannel,
        allChannels,
        searchTerm,
        sortType
    } = props;

    const regex = new RegExp(searchTerm, "gi");

    useEffect(() => {
        getAllRoomsData()
        
    },[])

    useEffect(() => {
        getAllRoomsData()
    },[props.roomsVisible, props.workspace[props.roomsVisible]])

    useEffect(() => {
        getWorkspaceData()
    },[props.workspace])

    useEffect(() => {
        console.log('sorttype changed')
        switchSort(allChannels, sortType)
        setSortingCount((prev) => prev + 1)
    },[sortType])



    const compareTimestamp = (t1 = null, t2 = null) => {
        if (t1 && t2) {return t2.timestamp - t1.timestamp}
        if (t1 && t2 == null) {return -1}
        if (t2 && t1 == null) {return 1}
        return 0
    }

    const compareTimestampLodashLatestFirst = (allChannels) => {
        const sorted = _.orderBy(allChannels, (channel) => {
        })
        props.setChannels(sorted);
        return (sorted);
    }

    const compareAlphabetLodashAtoZ = (allChannels) => {
        const sorted = _.sortBy(allChannels, (channel) => channel.roomName)
        // console.log('atoz')
        props.setChannels(sorted)
        return (sorted);
    }
    
    const compareAlphabetLodashZtoA = (allChannels) => {
        const sorted = _.sortBy(allChannels, (channel) => channel.roomName)
        // console.log('ztoa')
        props.setChannels(sorted.reverse())
        return (sorted.reverse());
    }
    
    const switchSort = (allChannels, sortType) => {
        // console.log(allChannels,"allChannels")
        switch (sortType) {
            case 0:
                return compareTimestampLodashLatestFirst(allChannels)

            case 1:
                return compareAlphabetLodashAtoZ(allChannels)

            case 2:
                return compareAlphabetLodashZtoA(allChannels)

            case 3:
                return compareTimestampLodashLatestFirst(allChannels)

            default:
                return compareTimestampLodashLatestFirst(allChannels)

        }
    }
    
    // console.log(allChannels,"before return")

    return(
            <>
                {
                    searchTerm && searchTerm.length > 0
                    ? allChannels
                        && allChannels
                            .filter(item => {
                                return item.roomName.match(regex) || (item.lastMessage && item.lastMessage.content && item.lastMessage.content.match(regex))
                            })
                            .sort((a, b) => switchSort(a, b, sortType))
                            .map((room, key) => (
                                <RoomItem
                                    roomData={room}
                                    key={key}
                                    index={key}
                                    currentChannel={currentChannel}
                                    workspace={workspace}
                                    workspaceData={workspaceData}
                                    allChannels={allChannels}
                                    {...props}
                                />
                            ))
                    : allChannels && 
                        allChannels.map((room, key) => {
                            return(
                            <RoomItem
                            roomData={room}
                            key={room.roomName + key}
                            index={key}
                            currentChannel={currentChannel}
                            workspace={workspace}
                            workspaceData={workspaceData}
                            {...props} 
                            />
                            )
                        })
                }

            </>
    )
}

const mapStateToProps = state => ({
    roomsVisible: state.workspace.roomsVisible,
    currentChannel: state.channel.currentChannel,
    allChannels: state.channel.allChannels,
    platform: state.channel.platform
})

export default connect(mapStateToProps, {
    setChannels,
    setCurrentChannel,
    setCurrentWorkspace,
    setParticipants,
    resetData
})(WorkspaceListElement);

Edit: I fixed it by using lodash cloneDeep. If anyone is stuck in a similar situation refer to this react-redux update item in array doesn't re-render

Shebu
  • 1
  • 1
  • 1
  • can you share the full components code ? – Mohammad Faisal Sep 22 '20 at 09:22
  • 1
    `My redux store updates perfectly` My guess is that you mutate the state so it doesn't update correctly. Are you using [Array.prototoype.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) because that will mutate the array. Try `[...orgArray].sort` instead. – HMR Sep 22 '20 at 09:24
  • @MohammadFaisal added the full component code – Shebu Sep 22 '20 at 09:32
  • @HMR I'm using dispatch to update the store and it's being sorted using lodash before dispatching – Shebu Sep 22 '20 at 09:36

0 Answers0