【问题标题】:Update Component After Store Loads, Using Selectors存储加载后更新组件,使用选择器
【发布时间】:2019-01-19 05:34:49
【问题描述】:

我目前在“Layout”componentDidMount 上初始化相关的商店数据(画廊和作品)。此数据是从 API 获取的。

const mapDispatchToProps = {
    GetRooms,
    GetPieces
}

class Layout extends React.Component {
    ...
    componentDidMount () {
        this.props.GetRooms()
        this.props.GetPieces()
    }
    ...
    render () {
        return (
            ...
            <Route path="/Gallery/:roomName" component={Gallery} />
            ...
        )
    }
}

我有一个单独的“Gallery”组件,它通过 Layout 组件内的 react-router Route 加载。 Gallery 的 mapStateToProps 使用选择器函数来过滤请求的画廊对象,并附加一个包含相关片段对象数组的属性。

const GetRoomByName = (state, roomName) => {
    const room = state.rooms.all.find(room =>
        room.Name === roomName
    )
    if (!room) return
    room.Pieces = state.pieces.all.filter(piece =>
        piece.RoomId === room.Id
    )
    return room
}

const mapStateToProps = (state, { match }) => ({
    room: GetRoomByName(state, decodeURIComponent(match.params.roomName))
})

class Gallery extends React.Component {
    ...
    render () {
        const { room } = this.props
        if (room === undefined) return <h3>Loading...</h3>
        return (
            ...
            {room.Pieces.map(piece =>
                ...
            )}
            ...
        )
    }
}

当我从主页导航到这个页面时,商店已经初始化并且选择器正常执行。

但是如果加载“Gallery”组件的路由被刷新或直接从地址栏加载,则数据还没有出现在存储中,并且在加载时组件不会更新。我可以运行控制台日志并渲染房间对象,但 Pieces 属性在加载到商店时不会触发重新渲染。

感谢您的帮助

【问题讨论】:

    标签: reactjs redux


    【解决方案1】:

    问题与connect 函数如何确定组件是否应该重新渲染有关。 connect 仅在 mapStateToProps 中的属性之一发生更改时重新呈现组件,使用浅比较确定。因为它使用浅比较,除非GetRoomByName 返回的引用发生变化,否则组件不会重新渲染。要解决此问题,您应该从 GetRoomByName 返回一个新对象,而不是修改该状态中存在的对象(这也可能导致其他人不得不在以后诊断问题)。

    const GetRoomByName = (state, roomName) => {
        const room = state.rooms.all.find(room =>
            room.Name === roomName
        );
        if (!room) return
        const pieces = state.pieces.all.filter(piece =>
            piece.RoomId === room.Id
        );
        return {
            ...room,
            Pieces: pieces
        };
    }
    

    这不是很有效,因为它每次都会返回一个新对象,导致组件比必要的更频繁地重新渲染。根据您的情况,这可能不是问题。如果是,你应该查看reselect,它会缓存GetRoomByName的结果。

    此外,您的代码在从主页导航时有效的原因是您返回的引用与 GetRoomByName 不同,因为 roomName 发生了变化。

    【讨论】:

    • 谢谢!那行得通。我不敢相信我没有意识到。所以关键是重新渲染的浅层比较。
    • 没问题!如果您以前没有见过,这不是最明显的诊断问题。你是对的,关键是浅比较。 connect 函数的操作类似于 React 纯组件。一旦你习惯了它,它实际上是一个主要的性能特性。我的经验法则是避免突变,因为它们具有意想不到的副作用,而是使用不可变的替代方案。
    猜你喜欢
    • 1970-01-01
    • 2013-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-18
    • 2012-12-17
    • 2019-01-21
    • 1970-01-01
    相关资源
    最近更新 更多