My redux store updates perfectly
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