Skip to content

Commit eb359b2

Browse files
committed
[BUGFIX] prevent reduntant rendering
1 parent 03b1d46 commit eb359b2

File tree

8 files changed

+163
-581
lines changed

8 files changed

+163
-581
lines changed

src/components/program/ProgramContentPlayer.tsx

Lines changed: 28 additions & 441 deletions
Large diffs are not rendered by default.

src/components/program/ProgramContentTrialModal.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,7 @@ const ProgramContentTrialModal: React.VFC<ProgramContentTrialModalProps> = ({
6969
{programContent && programContent.programContentBody && (
7070
<>
7171
{programContent.programContentBody.type === 'video' && (
72-
<ProgramContentPlayer
73-
programContentId={programContentId}
74-
programContentBody={programContent.programContentBody}
75-
isSwarmifyAvailable
76-
noAnnouncement
77-
/>
72+
<ProgramContentPlayer programContentId={programContentId} />
7873
)}
7974
{!BraftEditor.createEditorState(programContent.programContentBody.description).isEmpty() && (
8075
<BraftContent>{programContent.programContentBody.description}</BraftContent>

src/components/project/ProjectCardSection.tsx

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -404,16 +404,7 @@ const ProgramContentTrialPlayer: React.VFC<{
404404

405405
<StyledPlayerWrapper className="text-center">
406406
{onPrev && <Icon as={AngleThinLeftIcon} onClick={() => onPrev()} />}
407-
<ProgramContentPlayer
408-
programContentId={programContentId}
409-
programContentBody={{
410-
id: data.program_content_by_pk.program_content_body.id,
411-
type: '',
412-
description: '',
413-
data: data.program_content_by_pk.program_content_body.data,
414-
}}
415-
isSwarmifyAvailable={false}
416-
/>
407+
<ProgramContentPlayer programContentId={programContentId} />
417408
{onNext && <Icon as={AngleThinRightIcon} onClick={() => onNext()} />}
418409
</StyledPlayerWrapper>
419410
</>

src/contexts/ProgressContext.tsx

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useMutation, useQuery } from '@apollo/react-hooks'
22
import gql from 'graphql-tag'
33
import { flatten } from 'ramda'
4-
import React, { createContext } from 'react'
4+
import React, { createContext, useMemo } from 'react'
55
import hasura from '../hasura'
66

77
type ProgressProps = {
@@ -111,19 +111,22 @@ export const useProgramContentProgress = (programId: string, memberId: string) =
111111
{ variables: { programId, memberId } },
112112
)
113113

114-
const programContentProgress: ProgressProps['programContentProgress'] =
115-
loading || error || !data
116-
? undefined
117-
: flatten(
118-
data.program_content_body.map(contentBody =>
119-
contentBody.program_contents.map(content => ({
120-
programContentId: content.id,
121-
programContentSectionId: content.content_section_id,
122-
progress: content.program_content_progress[0]?.progress || 0,
123-
lastProgress: content.program_content_progress[0]?.last_progress || 0,
124-
})),
114+
const programContentProgress: ProgressProps['programContentProgress'] = useMemo(
115+
() =>
116+
loading || error || !data
117+
? undefined
118+
: flatten(
119+
data.program_content_body.map(contentBody =>
120+
contentBody.program_contents.map(content => ({
121+
programContentId: content.id,
122+
programContentSectionId: content.content_section_id,
123+
progress: content.program_content_progress[0]?.progress || 0,
124+
lastProgress: content.program_content_progress[0]?.last_progress || 0,
125+
})),
126+
),
125127
),
126-
)
128+
[data, error, loading],
129+
)
127130

128131
return {
129132
loadingProgress: loading,

src/hooks/program.ts

Lines changed: 87 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -349,92 +349,95 @@ export const useProgram = (programId: string) => {
349349
contents: ProgramContentProps[]
350350
})[]
351351
})
352-
| null =
353-
loading || error || !data || !data.program_by_pk
354-
? null
355-
: {
356-
id: data.program_by_pk.id,
357-
coverUrl: data.program_by_pk.cover_url,
358-
title: data.program_by_pk.title,
359-
abstract: data.program_by_pk.abstract,
360-
publishedAt: new Date(data.program_by_pk.published_at),
361-
isSubscription: data.program_by_pk.is_subscription,
362-
isSoldOut: data.program_by_pk.is_sold_out,
363-
listPrice: data.program_by_pk.list_price,
364-
salePrice: data.program_by_pk.sale_price,
365-
soldAt: data.program_by_pk.sold_at && new Date(data.program_by_pk.sold_at),
366-
description: data.program_by_pk.description,
367-
coverVideoUrl: data.program_by_pk.cover_video_url,
368-
isIssuesOpen: data.program_by_pk.is_issues_open,
369-
isPrivate: data.program_by_pk.is_private,
370-
isCountdownTimerVisible: data.program_by_pk.is_countdown_timer_visible,
371-
isIntroductionSectionVisible: data.program_by_pk.is_introduction_section_visible,
372-
tags: data.program_by_pk.program_tags.map(programTag => programTag.tag.name),
373-
categories: data.program_by_pk.program_categories.map(programCategory => ({
374-
id: programCategory.category.id,
375-
name: programCategory.category.name,
376-
})),
377-
roles: data.program_by_pk.program_roles.map(programRole => ({
378-
id: programRole.id,
379-
name: programRole.name as ProgramRoleName,
380-
memberId: programRole.member_id,
381-
memberName: programRole.member_id,
382-
})),
383-
plans: data.program_by_pk.program_plans.map(programPlan => ({
384-
id: programPlan.id,
385-
type: programPlan.type === 1 ? 'subscribeFromNow' : programPlan.type === 2 ? 'subscribeAll' : 'unknown',
386-
title: programPlan.title || '',
387-
description: programPlan.description,
388-
gains: programPlan.gains,
389-
currency: {
390-
id: programPlan.currency.id,
391-
label: programPlan.currency.label,
392-
unit: programPlan.currency.unit,
393-
name: programPlan.currency.name,
394-
},
395-
listPrice: programPlan.list_price,
396-
salePrice: programPlan.sale_price,
397-
soldAt: programPlan.sold_at && new Date(programPlan.sold_at),
398-
discountDownPrice: programPlan.discount_down_price,
399-
periodAmount: programPlan.period_amount,
400-
periodType: programPlan.period_type as PeriodType,
401-
startedAt: programPlan.started_at,
402-
endedAt: programPlan.ended_at,
403-
isParticipantsVisible: programPlan.is_participants_visible,
404-
publishedAt: programPlan.published_at,
405-
isCountdownTimerVisible: programPlan.is_countdown_timer_visible,
406-
})),
407-
contentSections: data.program_by_pk.program_content_sections.map(programContentSection => ({
408-
id: programContentSection.id,
409-
title: programContentSection.title,
410-
description: programContentSection.description,
411-
contents: programContentSection.program_contents.map(programContent => ({
412-
id: programContent.id,
413-
title: programContent.title,
414-
abstract: programContent.abstract,
415-
metadata: programContent.metadata,
416-
duration: programContent.duration,
417-
contentType:
418-
programContent.program_content_videos.length > 0
419-
? 'video'
420-
: programContent.program_content_type?.type || '',
421-
publishedAt: new Date(programContent.published_at),
422-
listPrice: programContent.list_price,
423-
salePrice: programContent.sale_price,
424-
soldAt: programContent.sold_at && new Date(programContent.sold_at),
425-
materials: programContent.program_content_materials.map(v => ({
426-
id: v.id,
427-
data: v.data,
428-
createdAt: v.created_at,
429-
})),
430-
videos: programContent.program_content_videos.map(v => ({
431-
id: v.attachment.id,
432-
size: v.attachment.size,
433-
options: v.attachment.options,
352+
| null = useMemo(
353+
() =>
354+
loading || error || !data || !data.program_by_pk
355+
? null
356+
: {
357+
id: data.program_by_pk.id,
358+
coverUrl: data.program_by_pk.cover_url,
359+
title: data.program_by_pk.title,
360+
abstract: data.program_by_pk.abstract,
361+
publishedAt: new Date(data.program_by_pk.published_at),
362+
isSubscription: data.program_by_pk.is_subscription,
363+
isSoldOut: data.program_by_pk.is_sold_out,
364+
listPrice: data.program_by_pk.list_price,
365+
salePrice: data.program_by_pk.sale_price,
366+
soldAt: data.program_by_pk.sold_at && new Date(data.program_by_pk.sold_at),
367+
description: data.program_by_pk.description,
368+
coverVideoUrl: data.program_by_pk.cover_video_url,
369+
isIssuesOpen: data.program_by_pk.is_issues_open,
370+
isPrivate: data.program_by_pk.is_private,
371+
isCountdownTimerVisible: data.program_by_pk.is_countdown_timer_visible,
372+
isIntroductionSectionVisible: data.program_by_pk.is_introduction_section_visible,
373+
tags: data.program_by_pk.program_tags.map(programTag => programTag.tag.name),
374+
categories: data.program_by_pk.program_categories.map(programCategory => ({
375+
id: programCategory.category.id,
376+
name: programCategory.category.name,
377+
})),
378+
roles: data.program_by_pk.program_roles.map(programRole => ({
379+
id: programRole.id,
380+
name: programRole.name as ProgramRoleName,
381+
memberId: programRole.member_id,
382+
memberName: programRole.member_id,
383+
})),
384+
plans: data.program_by_pk.program_plans.map(programPlan => ({
385+
id: programPlan.id,
386+
type: programPlan.type === 1 ? 'subscribeFromNow' : programPlan.type === 2 ? 'subscribeAll' : 'unknown',
387+
title: programPlan.title || '',
388+
description: programPlan.description,
389+
gains: programPlan.gains,
390+
currency: {
391+
id: programPlan.currency.id,
392+
label: programPlan.currency.label,
393+
unit: programPlan.currency.unit,
394+
name: programPlan.currency.name,
395+
},
396+
listPrice: programPlan.list_price,
397+
salePrice: programPlan.sale_price,
398+
soldAt: programPlan.sold_at && new Date(programPlan.sold_at),
399+
discountDownPrice: programPlan.discount_down_price,
400+
periodAmount: programPlan.period_amount,
401+
periodType: programPlan.period_type as PeriodType,
402+
startedAt: programPlan.started_at,
403+
endedAt: programPlan.ended_at,
404+
isParticipantsVisible: programPlan.is_participants_visible,
405+
publishedAt: programPlan.published_at,
406+
isCountdownTimerVisible: programPlan.is_countdown_timer_visible,
407+
})),
408+
contentSections: data.program_by_pk.program_content_sections.map(programContentSection => ({
409+
id: programContentSection.id,
410+
title: programContentSection.title,
411+
description: programContentSection.description,
412+
contents: programContentSection.program_contents.map(programContent => ({
413+
id: programContent.id,
414+
title: programContent.title,
415+
abstract: programContent.abstract,
416+
metadata: programContent.metadata,
417+
duration: programContent.duration,
418+
contentType:
419+
programContent.program_content_videos.length > 0
420+
? 'video'
421+
: programContent.program_content_type?.type || '',
422+
publishedAt: new Date(programContent.published_at),
423+
listPrice: programContent.list_price,
424+
salePrice: programContent.sale_price,
425+
soldAt: programContent.sold_at && new Date(programContent.sold_at),
426+
materials: programContent.program_content_materials.map(v => ({
427+
id: v.id,
428+
data: v.data,
429+
createdAt: v.created_at,
430+
})),
431+
videos: programContent.program_content_videos.map(v => ({
432+
id: v.attachment.id,
433+
size: v.attachment.size,
434+
options: v.attachment.options,
435+
})),
434436
})),
435437
})),
436-
})),
437-
}
438+
},
439+
[data, error, loading],
440+
)
438441

439442
return {
440443
loadingProgram: loading,

src/pages/ProgramContentPage/ProgramContentBlock.tsx

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
11
import { LockIcon } from '@chakra-ui/icons'
22
import { SkeletonText } from '@chakra-ui/react'
3-
import { StreamPlayerApi } from '@cloudflare/stream-react'
43
import axios from 'axios'
54
import BraftEditor from 'braft-editor'
65
import { throttle } from 'lodash'
76
import { useApp } from 'lodestar-app-element/src/contexts/AppContext'
87
import { useAuth } from 'lodestar-app-element/src/contexts/AuthContext'
9-
import LanguageContext from 'lodestar-app-element/src/contexts/LanguageContext'
108
import { flatten, includes } from 'ramda'
11-
import React, { useContext, useEffect, useRef } from 'react'
9+
import React, { useContext, useEffect } from 'react'
1210
import { useIntl } from 'react-intl'
1311
import styled from 'styled-components'
1412
import { BraftContent } from '../../components/common/StyledBraftEditor'
@@ -17,7 +15,7 @@ import ProgramContentPlayer from '../../components/program/ProgramContentPlayer'
1715
import { ProgressContext } from '../../contexts/ProgressContext'
1816
import { productMessages } from '../../helpers/translation'
1917
import { useProgramContent } from '../../hooks/program'
20-
import { ProgramContentProps, ProgramContentSectionProps, ProgramProps, ProgramRoleProps } from '../../types/program'
18+
import { ProgramContentProps, ProgramContentSectionProps, ProgramRoleProps } from '../../types/program'
2119
import { StyledContentBlock } from './index.styled'
2220
import ProgramContentCreatorBlock from './ProgramContentCreatorBlock'
2321
import ProgramContentExerciseBlock from './ProgramContentExerciseBlock'
@@ -36,27 +34,25 @@ const StyledTitle = styled.h3`
3634
`
3735

3836
const ProgramContentBlock: React.VFC<{
39-
program: ProgramProps & {
40-
roles: ProgramRoleProps[]
41-
contentSections: (ProgramContentSectionProps & { contents: ProgramContentProps[] })[]
42-
}
37+
programId: string
38+
programRoles: ProgramRoleProps[]
39+
programContentSections: (ProgramContentSectionProps & { contents: ProgramContentProps[] })[]
4340
programContentId: string
44-
}> = ({ program, programContentId }) => {
45-
const { currentLanguage } = useContext(LanguageContext)
41+
issueEnabled?: boolean
42+
}> = ({ programId, programRoles, programContentSections, programContentId, issueEnabled }) => {
4643
const { formatMessage } = useIntl()
4744
const { loading: loadingApp, enabledModules, settings } = useApp()
4845
const { authToken } = useAuth()
4946
const { programContentProgress, refetchProgress, insertProgress } = useContext(ProgressContext)
5047
const { loadingProgramContent, programContent } = useProgramContent(programContentId)
51-
const streamRef = useRef<StreamPlayerApi>()
5248

53-
const instructor = program.roles.filter(role => role.name === 'instructor')[0]
49+
const instructor = programRoles.filter(role => role.name === 'instructor')[0]
5450

5551
const programContentBodyType = programContent?.programContentBody?.type
5652
const initialProgress =
5753
programContentProgress?.find(progress => progress.programContentId === programContentId)?.progress || 0
5854

59-
const nextProgramContent = flatten(program.contentSections.map(v => v.contents)).find(
55+
const nextProgramContent = flatten(programContentSections.map(v => v.contents)).find(
6056
(_, i, contents) => contents[i - 1]?.id === programContentId,
6157
)
6258

@@ -74,7 +70,7 @@ const ProgramContentBlock: React.VFC<{
7470
insertProgress(programContentId, {
7571
progress: 1,
7672
lastProgress: 1,
77-
}).then(() => refetchProgress())
73+
})
7874
}, [
7975
initialProgress,
8076
insertProgress,
@@ -87,7 +83,6 @@ const ProgramContentBlock: React.VFC<{
8783
if (loadingApp || loadingProgramContent || !programContent || !insertProgress || !refetchProgress) {
8884
return <SkeletonText mt="1" noOfLines={4} spacing="4" />
8985
}
90-
9186
const insertProgramProgress = throttle(async (progress: number) => {
9287
const currentProgress = Math.ceil(progress * 20) / 20 // every 5% as a tick
9388
return await insertProgress(programContentId, {
@@ -109,7 +104,6 @@ const ProgramContentBlock: React.VFC<{
109104
key={programContent.id}
110105
programContentId={programContentId}
111106
nextProgramContent={nextProgramContent}
112-
isSwarmifyAvailable={settings['feature.swarmify.enabled'] === '1'}
113107
onVideoEvent={e => {
114108
if (e.type === 'progress') {
115109
insertProgramProgress(e.progress)
@@ -131,8 +125,6 @@ const ProgramContentBlock: React.VFC<{
131125
.catch(() => {})
132126
if (e.type === 'ended') {
133127
insertProgramProgress(1)?.then(() => refetchProgress())
134-
} else {
135-
refetchProgress()
136128
}
137129
}
138130
}}
@@ -167,7 +159,12 @@ const ProgramContentBlock: React.VFC<{
167159
<ProgramContentExerciseBlock programContent={programContent} nextProgramContentId={nextProgramContent?.id} />
168160
)}
169161

170-
<ProgramContentTabs program={program} programContent={programContent} />
162+
<ProgramContentTabs
163+
programId={programId}
164+
programRoles={programRoles}
165+
programContent={programContent}
166+
issueEnabled={issueEnabled}
167+
/>
171168

172169
{programContent.programContentBody?.type !== 'practice' && (
173170
<ProgramContentCreatorBlock memberId={instructor.memberId} />

0 commit comments

Comments
 (0)