了解子组件中的React js构造函数

时间:2019-10-29 23:08:06

标签: reactjs redux constructor

我想了解react组件构造函数的行为。假设我有三个组件-PageComponent,ListComponent和ItemComponent。我的伪代码结构是:

PageComponent(从redux获取数据,获取数据)
ListComponent(获取数据作为道具,在循环中(地图)呈现ItemComponents的列表)
ItemComponent(获取道具数据,渲染道具,操纵数据)

逻辑:  -当ItemComponent中的数据发生更改时,更改将存储在REDUX中,并且此更改导致列表重新呈现。

用例1:
  -PageComponent呈现ListComponent,而ListComponent呈现ItemComponets的列表
  -在REDUX listItem数据更改时,将更新PageComponent,将更新ListComponent,并调用ItemComponent CONSTRUCTOR(重置其本地状态)

用例2:
 -PageComponent仅呈现ItemComponents的LIST(使用映射循环)。
 -当REDUX listItem数据更改时,PageComponent会更新,而不会调用ItemComponent CONSTRUCTOR(组件“仅”更新)(并且不会重置其本地状态)

为什么这些示例中的行为不同?

源代码: PageComponent:

import React from 'react'
...


class UsersPage extends React.Component {

    constructor(props) {
        super(props)
        props.actions.getUsers();
    }

    render() {

        const {users} = this.props


        return (
            <Main>
                {/* // NO ITEM CONSTRUCTOR IS CALLED
                    users.data.items.map((item, index) => {
                        return <ListItemComponent
                            data={item}
                            itemMethods={{
                                getItem: (data) => this.props.actions.getUser(data),
                                onEdit: (data) => this.props.actions.updateUser(data),
                                onDelete: (data) => this.props.actions.deleteUser(data),
                                validation: (data) => validateInput(this.props.strings, data)
                            }}
                            key={index}
                        />
                    })*/
                }
                { // ITEM CONSTRUCTOR IS CALLED
                <ListComponent
                    loading={users.isFetching}
                    data={users.data}
                    methods={{
                        getItem: (data) => this.props.actions.getUser(data),
                        onEdit: (data) => this.props.actions.updateUser(data),
                        onDelete: (data) => this.props.actions.deleteUser(data),
                        validation: (data) => validateInput(this.props.strings, data)
                    }}
                />}
            </Main>
        );
    }
}

UsersPage.propTypes = {
    users: PropTypes.object.isRequired,
    strings: PropTypes.object.isRequired,
}

function mapStateToProps(state) {
    return {
        users: state.users,
        strings: state.strings.data || {},
    };
}

function mapDispatchToProps(dispatch) {
    return {
        actions: bindActionCreators({
            getUsers,
            getUser,
            addUser,
            updateUser,
            deleteUser,
        }, dispatch)
    };
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(withAlert(UsersPage));

ListComponent:

import React from 'react'
...

class ListComponent extends React.Component {

    getList() {
        return <div className="list-outer">
           <Row>
             {
              items.map((item, index) => {
                 return <ListItemComponent
                           data={item}
                           itemMethods={methods}
                           key={index}
                         />
              })
              }
           </Row>
        </div>
    }

    render() {
        const {loading} = this.props

        return (
            <div className="list-wrapper">
                {
                    loading ? <Spinner visible={true}/>
                        :
                        this.getList()
                }
            </div>
        )
    }
}


ListComponent.propTypes = {
    loading: PropTypes.bool.isRequired,
    data: PropTypes.object.isRequired,
    methods: PropTypes.object.isRequired,
}

export default ListComponent

ListItemComponent:

import React from 'react'
...

class ListItemComponent extends React.Component {

    constructor(props) {
        super(props)
        this.state = {
            editMode: false,
        }
    }

    toggleEditMode(){
        const editMode = this.state.editMode
        this.setState({editMode: !editMode})   
    }

    onEdit(id) {
        const itemMethods = this.props.itemMethods
        this.toggleEditMode()
        itemMethods.getItem({id: id})
    }

    onDelete(item) {
        //...
    }

    getFields(rowData, index) {
        return <div key={index}>
                {
                 rowData.map((itm, idx) => {
                   return <div key={idx}>{itm.label}: {itm.value}</div>
                 })
                }
            </div>
    }

    render() {
        const editMode = this.state.editMode
        const {data, itemMethods, strings} = this.props
        return (
            editMode ?
                <Form
                    id={data.id}
                    onSubmit={(data) => itemMethods.onEdit(data)}
                    validation={(data) => itemMethods.validation(data)}
                    onCloseForm={() => this.toggleEditMode()}
                />
                :
                <Col xs={12}>
                    <div>
                        <div
                            {this.getFields(data)}
                        </div>
                        <div className="controls">
                             <button
                                  className="btn btn-theme inverse danger"
                                  onClick={() => this.onDelete(data)}
                             >{strings.delete}</button>

                            <button
                                onClick={() => this.onEdit(data.id)}
                                className="btn btn-theme"               type="button"
                            >
                                {strings.edit}
                            </button>
                        </div>
                    </div>
                </Col>
        )
    }
}


ListItemComponent .propTypes = {
    strings: PropTypes.object.isRequired,
    data: PropTypes.object.isRequired,
    itemMethods: PropTypes.object.isRequired,
}


function mapStateToProps(state) {
    return {
        strings: state.strings.data || {}
    };
}


export default connect(
    mapStateToProps,
    null,
)(ListItemComponent )

2 个答案:

答案 0 :(得分:0)

确保每个ItemComponent都有一个key道具集。当React渲染项目列表时,它需要知道如何识别每个元素,React则由您自己决定。如果省略key道具,React将在每次重新渲染时销毁并重新创建列表,这意味着调用组件构造函数。

如果您提供所使用的确切代码,我们可以更好地指出您问题的出处。

您可以了解有关列表和键here的更多信息。

答案 1 :(得分:0)

已解决

这是由ListComponent和作为渲染条件中的条件放置的加载道具引起的。编辑项目时,道具加载设置为true,微调器变为可见,并且它是ListComponent中的唯一元素,因此列表项已卸载