【问题标题】:Understanding react js constructor in children component了解子组件中的 React js 构造函数
【发布时间】:2020-02-25 05:38:03
【问题描述】:

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

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

逻辑: - 当 ItemComponent 中的数据发生变化时,变化会存储在 REDUX 中,这种变化会导致列表重新渲染。

用例 1:
- PageComponent 呈现 ListComponent 和 ListComponent 呈现 ItemComponets 列表
- 当 REDUX listItem 数据变化时,PageComponent 被更新,ListComponent 被更新并且 ItemComponent CONSTRUCTOR 被调用(它的本地状态被重置)

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

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

源代码: 页面组件:

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));

列表组件:

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

列表项组件:

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 )

【问题讨论】:

    标签: reactjs redux constructor


    【解决方案1】:

    确保每个 ItemComponent 都有一个 key 属性集。当 React 呈现你的项目列表时,它需要知道如何识别每个元素,而 React 让你来做这件事。如果你省略了 key 属性,React 将在每次重新渲染时销毁并重新创建你的列表,这意味着调用组件构造函数。

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

    您可以阅读有关列表和键的更多信息here

    【讨论】:

    • 是的,每个 ItemComponent 都有一个 KEY 属性。我通过添加一些代码更新了我的问题。
    【解决方案2】:

    已解决

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-04-30
      • 2014-08-04
      • 1970-01-01
      • 1970-01-01
      • 2020-05-23
      • 1970-01-01
      • 1970-01-01
      • 2018-10-22
      相关资源
      最近更新 更多