Skip to content

Commit

Permalink
feat: 完成组件的 hook 化
Browse files Browse the repository at this point in the history
  • Loading branch information
fjc0k committed Aug 25, 2019
1 parent d18d5c7 commit 5148b25
Show file tree
Hide file tree
Showing 15 changed files with 667 additions and 717 deletions.
8 changes: 4 additions & 4 deletions src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ class App extends Taro.Component {
pages: [
'pages/Home',
// @index('./pages/*[!Home].tsx', (pp, cc) => `'${pp.path.replace(/^\.\//, '')}',`)
// 'pages/DatePicker',
// 'pages/ECharts',
'pages/DatePicker',
'pages/ECharts',
'pages/Picker',
'pages/PickerView',
'pages/Popup',
// 'pages/SinglePicker',
'pages/SinglePicker',
'pages/Sticky',
// 'pages/TimePicker',
'pages/TimePicker',
// 'pages/Transition',
// @endindex
],
Expand Down
244 changes: 106 additions & 138 deletions src/components/DatePicker/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import dayjs from 'dayjs'
import MPicker from '../Picker'
import Taro from '@tarojs/taro'
import { CascadedData } from '../PickerView'
import { component } from '../component'
import { MDatePickerProps } from './props'
import MPicker, { MPickerProps } from '../Picker'
import Taro, { useEffect, useState } from '@tarojs/taro'
import { functionalComponent } from '../component'
import { MDatePickerDefaultProps, MDatePickerProps } from './props'
import { memoize } from 'vtils'
import { MPickerCascadedData } from '../Picker/types'

const getDaysInMonth = memoize(
(month: number, year: number) => {
Expand All @@ -16,162 +16,130 @@ const getDaysInMonth = memoize(
},
)

/**
* 日期选择器组件。
*
* @example
*
* ```jsx
* <MDatePicker
* title='选择日期'
* selectedDate={selectedDate}
* onConfirm={selectedDate => this.setState({ selectedDate })}>
* <Text>选择日期</Text>
* </MDatePicker>
* ```
*/
class MDatePicker extends component({
props: MDatePickerProps,
state: {
localData: [] as CascadedData,
localSelectedIndexes: [] as number[],
},
}) {
lastUpdateAt: number = 0

lastSelectedIndexes: number[] = []
function MDatePicker(props: MDatePickerProps) {
const [data, setData] = useState<MPickerCascadedData>([])
const [selectedIndexes, setSelectedIndexes] = useState<number[]>([])

componentDidMount() {
this.updateLocalState(this.props)
}
useEffect(
() => {
let reject: boolean | void = false

componentWillReceiveProps(nextProps: MDatePicker['props']) {
// perf: 极短时间内的行为应是由子组件触发的父组件更新
if (this.lastUpdateAt && (Date.now() - this.lastUpdateAt < 60)) {
this.setState({
localSelectedIndexes: this.lastSelectedIndexes,
})
} else {
this.updateLocalState(nextProps)
}
}
const startDate = dayjs(props.startDate)
const startYear = startDate.year()
const startMonth = startDate.month() + 1
const startDay = startDate.date()

updateLocalState(props: MDatePicker['props']) {
let reject: boolean | void = false
const endDate = dayjs(props.endDate)
const endYear = endDate.year()
const endMonth = endDate.month() + 1
const endDay = endDate.date()

const startDate = dayjs(props.startDate)
const startYear = startDate.year()
const startMonth = startDate.month() + 1
const startDay = startDate.date()
const useRawYearValue = props.formatYear == null
const useRawMonthValue = props.formatMonth == null
const useRawDayValue = props.formatDay == null

const endDate = dayjs(props.endDate)
const endYear = endDate.year()
const endMonth = endDate.month() + 1
const endDay = endDate.date()

const useRawYearValue = props.formatYear == null
const useRawMonthValue = props.formatMonth == null
const useRawDayValue = props.formatDay == null

const yearList: CascadedData = []
const selectedIndexes: number[] = []
for (let year = startYear; year <= endYear; year++) {
reject = props.filterYear && props.filterYear({ year: year })
if (reject !== true) {
if (year === props.selectedDate[0]) {
selectedIndexes[0] = yearList.length
}
const monthList: CascadedData = []
yearList.push({
label: String(useRawYearValue ? year : props.formatYear({ year })),
value: year,
children: monthList,
})
const months = year === endYear ? endMonth : 12
for (let month = (year === startYear ? startMonth : 1); month <= months; month++) {
reject = props.filterMonth && props.filterMonth({
year: year,
month: month,
const yearList: MPickerCascadedData = []
const selectedIndexes: number[] = []
for (let year = startYear; year <= endYear; year++) {
reject = props.filterYear && props.filterYear({ year: year })
if (reject !== true) {
if (year === props.selectedDate[0]) {
selectedIndexes[0] = yearList.length
}
const monthList: MPickerCascadedData = []
yearList.push({
label: String(useRawYearValue ? year : props.formatYear({ year })),
value: year,
children: monthList,
})
if (reject !== true) {
if (month === props.selectedDate[1]) {
selectedIndexes[1] = monthList.length
}
const dayList: CascadedData = []
monthList.push({
label: String(useRawMonthValue ? month : props.formatMonth({ year, month })),
value: month,
children: dayList,
const months = year === endYear ? endMonth : 12
for (let month = (year === startYear ? startMonth : 1); month <= months; month++) {
reject = props.filterMonth && props.filterMonth({
year: year,
month: month,
})
const days = year === endYear && month === endMonth ? endDay : getDaysInMonth(month, year)
for (let day = (year === startYear && month === startMonth ? startDay : 1); day <= days; day++) {
reject = props.filterDay && props.filterDay({
year: year,
month: month,
day: day,
if (reject !== true) {
if (month === props.selectedDate[1]) {
selectedIndexes[1] = monthList.length
}
const dayList: MPickerCascadedData = []
monthList.push({
label: String(useRawMonthValue ? month : props.formatMonth({ year, month })),
value: month,
children: dayList,
})
if (reject !== true) {
if (day === props.selectedDate[2]) {
selectedIndexes[2] = dayList.length
}
dayList.push({
label: String(useRawDayValue ? day : props.formatDay({ year, month, day })),
value: day,
const days = year === endYear && month === endMonth ? endDay : getDaysInMonth(month, year)
for (let day = (year === startYear && month === startMonth ? startDay : 1); day <= days; day++) {
reject = props.filterDay && props.filterDay({
year: year,
month: month,
day: day,
})
} else {
reject = false
if (reject !== true) {
if (day === props.selectedDate[2]) {
selectedIndexes[2] = dayList.length
}
dayList.push({
label: String(useRawDayValue ? day : props.formatDay({ year, month, day })),
value: day,
})
} else {
reject = false
}
}
selectedIndexes[2] = selectedIndexes[2] == null ? 0 : selectedIndexes[2]
} else {
reject = false
}
selectedIndexes[2] = selectedIndexes[2] == null ? 0 : selectedIndexes[2]
} else {
reject = false
}
selectedIndexes[1] = selectedIndexes[1] == null ? 0 : selectedIndexes[1]
} else {
reject = false
}
selectedIndexes[1] = selectedIndexes[1] == null ? 0 : selectedIndexes[1]
} else {
reject = false
}
}
selectedIndexes[0] = selectedIndexes[0] == null ? 0 : selectedIndexes[0]
selectedIndexes[0] = selectedIndexes[0] == null ? 0 : selectedIndexes[0]

this.setState({
localData: yearList,
localSelectedIndexes: selectedIndexes,
})
}
setData(yearList)
setSelectedIndexes(selectedIndexes)
},
[
props.startDate,
props.endDate,
props.filterYear,
props.filterMonth,
props.filterDay,
props.formatYear,
props.formatMonth,
props.formatDay,
],
)

handleConfirm: MPicker['props']['onConfirm'] = selectedIndexes => {
const { localData } = this.state
const handleConfirm: MPickerProps['onConfirm'] = selectedIndexes => {
const selectedDate: number[] = []
let list = localData
const n = Math.min(selectedIndexes.length, 3)
for (let i = 0; i < n; i++) {
for (
let i = 0,
n = Math.min(selectedIndexes.length, 3),
list = data;
i < n;
i++
) {
if (!list[selectedIndexes[i]]) break
selectedDate.push(list[selectedIndexes[i]].value)
list = list[selectedIndexes[i]].children
if (!list) break
}
this.lastUpdateAt = Date.now()
this.lastSelectedIndexes = selectedIndexes
this.props.onConfirm(selectedDate)
props.onConfirm(selectedDate)
}

render() {
const {
localData,
localSelectedIndexes,
} = this.state

return !localData.length ? this.props.children : (
<MPicker
{...this.props}
data={localData}
selectedIndexes={localSelectedIndexes}
onConfirm={this.handleConfirm}>
{this.props.children}
</MPicker>
)
}
return !data.length ? props.children : (
<MPicker
{...props}
data={data}
selectedIndexes={selectedIndexes}
onConfirm={handleConfirm}>
{props.children}
</MPicker>
)
}

export default MDatePicker
export default functionalComponent(MDatePickerDefaultProps)(MDatePicker)
Loading

0 comments on commit 5148b25

Please sign in to comment.