使用选择器在存储加载后更新组件

时间:2018-08-12 06:12:04

标签: reactjs redux

我目前正在“布局” 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} />
            ...
        )
    }
}

我有一个单独的“图库”组件,该组件通过Layout组件内的react-route路由加载。 Gallery的mapStateToProps使用选择器功能过滤请求的Gallery对象,并附加一个包含相关片断对象数组的属性。

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 =>
                ...
            )}
            ...
        )
    }
}

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

但是,如果刷新或加载了从地址栏中直接加载“图库”组件的路由,则存储中尚不存在数据,并且在加载时该组件也不会更新。我可以运行控制台日志,并渲染room对象,但是Pieces属性在加载到商店中时不会触发重新渲染。

谢谢您的帮助

1 个答案:

答案 0 :(得分:0)

问题与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