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({
             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={{  '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;
                    }
                }
            }
        }
    }
}
原文地址:https://www.cnblogs.com/Nyan-Workflow-FC/p/13744040.html