taro3.x父组件更新,子组件同步更新问题解决
子组件sandCommon:
import React, { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import {
View,
MovableArea,
MovableView,
Image,
Text,
Label,
CheckboxGroup,
Checkbox
} from '@tarojs/components'
import classnames from 'classnames'
import { includes, find } from 'lodash'
import api from '@services/api'
import app from '@services/request'
import './common.scss'
interface ISandState {
value: string
text: string
checked: boolean
}
const INIT_SAND_STATE: ISandState[] = [
{
value: '1',
text: '在售',
checked: true
},
{
value: '2',
text: '待售',
checked: true
},
{
value: '3',
text: '售完',
checked: true
}
]
interface IShowState {
show: boolean
text: string
}
const INIT_SAND_DATA = {
sandBuilding: []
}
const INIT_SHOW_STATE = { show: true, text: '收起' }
interface IProps {
houseId: string,
outerWidth?: number,
outerHeight: number,
currentBuilding?: any,
setCurrentBuilding: (any) => void,
updateSandBuilding: (any) => void
}
const SandCommon = (props: IProps) => {
const { houseId, outerHeight, currentBuilding = {} } = props
const [movableView, setMovableView] = useState<any>({})
const [showState, setShowState] = useState<IShowState>(INIT_SHOW_STATE)
const [sandState, setSandState] = useState<ISandState[]>(INIT_SAND_STATE)
const [sandData, setSandData] = useState<any>(INIT_SAND_DATA)
const [sandBuilding, setSandBuilding] = useState<any>(INIT_SAND_DATA.sandBuilding)
const [current, setCurrent] = useState<any>({})
const safeArea = Taro.getSystemInfoSync().safeArea
const outerWidth = props.outerWidth ? props.outerWidth : safeArea.width
useEffect(() => {
fetchSand()
}, [houseId])
useEffect(() => {
setCurrent(currentBuilding)
}, [currentBuilding])
const handleSandImageLoad = (e: any) => {
setMovableView({
width: e.detail.width,
height: e.detail.height
})
}
const fetchSand = () => {
app.request({
url: app.areaApiUrl(api.getHouseSand),
data: {
id: houseId
}
}).then((result: any) => {
setSandData(result)
showSandBuilding(INIT_SAND_STATE, result.sandBuilding)
props.updateSandBuilding(result.sandBuilding)
})
}
const toggleShowState = () => {
setShowState({
show: !showState.show,
text: showState.show ? '展开' : '收起'
})
}
const handleCheckboxChange = (e: any) => {
const values = e.detail.value
for (const item of sandState) {
if (includes(values, item.value)) {
item.checked = true
} else {
item.checked = false
}
}
setSandState(sandState)
showSandBuilding(sandState, sandData.sandBuilding)
}
const showSandBuilding = (sandState, allSandBUilding) => {
let sandBuilding: any[] = []
for (const item of allSandBUilding) {
const target = find(sandState, { value: item.sale_status })
if (target.checked) {
sandBuilding.push(item)
}
}
setSandBuilding(sandBuilding)
}
const switchCurrent = (item: any) => {
props.setCurrentBuilding(item)
}
return (
<View className="sand-card" style={{ width: '100%', height: outerHeight }}>
<MovableArea className="sand-area">
<MovableView
x={(outerWidth - movableView.width) / 2}
y={(outerHeight - movableView.height) / 2}
style={movableView}
className="sand-view"
direction="all"
animation={false}
>
<Image
className="sand-image"
src={sandData.fang_sand_pic}
onLoad={handleSandImageLoad}
/>
{
sandBuilding.map((item: any, index: number) => (
<View
key={index}
style={item.style}
className={classnames('sand-item', `sale-status-${item.sale_status}`, current.id === item.id && 'actived')}
onClick={() => switchCurrent(item)}
>
<Text>{item.name}</Text>
<Text className="triangle-down"></Text>
</View>
))
}
</MovableView>
</MovableArea>
<View className="sand-state">
<CheckboxGroup
onChange={handleCheckboxChange}
className={classnames('sand-state-box', !showState.show && 'hide')}
>
{
sandState.map((item: any, index: any) => (
<Label
key={index}
for={index}
className={classnames('check-label', `sale-status-${item.value}`)}
>
<Checkbox
id={index}
className="check-box"
value={item.value}
checked={item.checked}
>
</Checkbox>
<Text className="check-text">{item.text}</Text>
</Label>
))
}
</CheckboxGroup>
<View className="sand-state-btn" onClick={toggleShowState}>{showState.text}</View>
</View>
</View>
)
}
export default SandCommon
使用useMemo + useEffect监听props更新的字段:
useEffect(() => {
fetchSand()
}, [houseId])监听houseId发生变化重新渲染
const getSandCommonComponent = useMemo(() => { return ( <SandCommon houseId={houseData.id} outerHeight={200} currentBuilding={{}} setCurrentBuilding={toHouseSand} updateSandBuilding={() => { }} /> ) }, [houseData.id])
const { currentBuilding = {}} = props
useEffect(() => {
setCurrent(currentBuilding)
}, [currentBuilding])监听currentBuilding发生变化重新渲染
父组件HouseSand:
import React, { useEffect, useMemo, useState } from 'react'
import Taro from '@tarojs/taro'
import {
View,
Text,
ScrollView
} from '@tarojs/components'
import classnames from 'classnames'
import api from '@services/api'
import app from '@services/request'
import NavBar from '@components/navbar'
import SandCommon from '@house/pages/new/sand/common'
import '@styles/common/house.scss'
import '@house/styles/common.scss'
import './index.scss'
const INIT_SAND_BUILDING = []
const HouseSand = () => {
const INTI_CURRENT = { id: '167' }
const [sandBuilding, setSandBuilding] = useState<any>(INIT_SAND_BUILDING)
const [roomData, setRoomData] = useState<any[]>([])
const [current, setCurrent] = useState<any>(INTI_CURRENT)
useEffect(() => {
fetchRoom()
}, [current.id])
const safeArea = Taro.getSystemInfoSync().safeArea
const fetchRoom = () => {
app.request({
url: app.areaApiUrl(api.getHouseSandRoom),
data: {
id: current.id
}
}).then((result: any) => {
setRoomData(result)
})
}
const handleRoomCheck = (item: any) => {
console.log(item)
}
const getSandCommonComponent = useMemo(() => {
return (
<SandCommon
outerWidth={safeArea.width}
outerHeight={300}
currentBuilding={current}
setCurrentBuilding={(currentBuilding) => setCurrent(currentBuilding)}
updateSandBuilding={(sandBuilding) => setSandBuilding(sandBuilding)}
></SandCommon>
)
}, [current])
return (
<View className="sand">
<NavBar title="楼盘沙盘图"></NavBar>
<View className="sand-wrapper">
{getSandCommonComponent}
<View className="sand-content">
<View className="sand-info">
<ScrollView
className="sand-info-header"
scrollX
scrollIntoView={`view_${current.id}`}
>
<View className="sand-list">
{
sandBuilding.map((item: any, index: number) => (
<View
key={index}
id={`view_${item.id}`}
className={classnames('sand-item', current.id === item.id && 'actived')}
onClick={() => setCurrent(item)}
>{item.name}
</View>
))
}
</View>
</ScrollView>
<View className="sand-info-detail">
<View className="sand-info-detail-content view-content">
<View className="detail-item">
<Text className="label">规划户数:</Text>
<Text>{current.plan_households}</Text>
</View>
<View className="detail-item">
<Text className="label">楼层:</Text>
<Text>{current.storey_height}</Text>
</View>
<View className="detail-item">
<Text className="label">梯户配比:</Text>
<Text>{current.elevator_number}梯{current.elevator_households}户</Text>
</View>
</View>
<View className="sand-info-detail-room mt20">
<View className="room-header">
<Text className="title">户型</Text>
</View>
<View className="room-list">
{
roomData.length > 0 ?
roomData.map((item: any, index: number) => {
const itemData = item.fangHouseBuildingRoom
return (
<View key={index} className="room-item">
<Text className="item-text">{itemData.name}</Text>
<Text className="item-text">{itemData.room}室{itemData.office}厅{itemData.toilet}卫</Text>
<Text className="item-text">{itemData.building_area}㎡</Text>
<Text className="item-btn" onClick={() => handleRoomCheck(itemData)}>查看</Text>
</View>
)
}) :
<View className="room-item">
<Text className="item-text">暂无数据</Text>
</View>
}
</View>
</View>
</View>
</View>
</View>
</View>
</View>
)
}
export default HouseSand
当current发生变化后更新子组件:
const getSandCommonComponent = useMemo(() => { return ( <SandCommon outerWidth={safeArea.width} outerHeight={300} currentBuilding={current} setCurrentBuilding={(currentBuilding) => setCurrent(currentBuilding)} updateSandBuilding={(sandBuilding) => setSandBuilding(sandBuilding)} ></SandCommon> ) }, [current])
子组件样式:
.sand-card { position: relative; .sand-state { display: flex; justify-content: center; align-items: center; position: absolute; right: 30px; bottom: 30px; &-box { flex: auto; height: 60px; line-height: 60px; font-size: $font-basic; padding: 0 40px 0 20px; margin-right: -30px; border-radius: 30px; background-color: rgba($color: $white, $alpha: 0.9); transition: 0.3s; &.hide { width: 0; padding: 0; overflow: hidden; } .check-label { margin: 0 10px; padding: 2px 16px; border-radius: 20px; .check-box { vertical-align: 2px; .wx-checkbox-input { width: 30px; height: 30px; } } .check-text { color: $white; } } } &-btn { width: 90px; height: 90px; line-height: 90px; font-size: $font-basic; border-radius: 50%; text-align: center; background-color: $white; color: $title-color; } } .sand-area { width: 100%; height: 100%; overflow: hidden; background-color: $bg-color; .sand-view { .sand-image { width: 100%; height: 100%; } .sand-item { position: absolute; font-size: $font-basic; padding: 10px 16px; border-radius: $border-radius-base; color: $white; .triangle-down { position: absolute; top: 54px; left: 16px; display: block; border-style: solid; border-width: 16px 16px 0; } &.actived { background-color: $primary-color; color: $white; .triangle-down { border-color: $primary-color transparent transparent; } } } } } }

浙公网安备 33010602011771号