父状态更改时如何防止子组件重新呈现

时间:2019-04-19 00:31:10

标签: reactjs frontend

我有两个无状态组件和一个有状态组件。在我的有状态组件中,我有一个人员列表,当我单击其中的一个时,它会打开一个模式。我基本上将模态的状态存储在有状态组件中,并将值作为道具发送给模态。因此,只要打开模型并重新渲染所有内容,它就会随时更改状态。

如何在更改状态后阻止重新渲染无状态类?

我在无状态组件中尝试过备忘录,但是没有运气

模块组件

const modal = React.memo((props) => {

    return (
    <Modal show={props.show} onHide={props.handleClose} aria-labelledby="contained-modal-title-vcenter"
           centered>
        <Modal.Header closeButton>
            <Modal.Title>Modal heading</Modal.Title>
        </Modal.Header>
        <Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
        <Modal.Footer>
            <Button variant="secondary" onClick={props.handleClose}>
                Close
            </Button>
        </Modal.Footer>
    </Modal>
    )
});

export default modal

人员组成部分

const person = React.memo((props) => {
    console.log("render");
    return (
        <article className="Person" onClick={props.clicked}>
            <Container>
                <Row>
                    <Col>
                        <p style={{marginBottom: 0 + 'px', marginTop: 1 + 'rem'}}><b>{props.name}</b></p>
                        <div className="Organization-wrapper">
                            <FontAwesomeIcon className="Organization-icon" icon={faBuilding}/><p>{props.company}</p>
                        </div>
                    </Col>
                    <Col>
                        <div>
                            {
                                props.image ?
                                    <img src={props.image} height="50" width="50" className="Person-image"
                                         alt="avatar"/>
                                    : <svg height="50" width="50" className="Person-image">
                                        <rect fill="cornflowerblue" x="0" y="0" height="50" width="50"/>
                                        <text
                                            fill="#ffffff"
                                            fontSize="20"
                                            textAnchor="middle"
                                            x="25"
                                            y="30">{props.first_char.toUpperCase()}</text>
                                    </svg>
                            }
                        </div>
                    </Col>
                </Row>
            </Container>
        </article>
    );
});

状态组件

class PersonList extends Component {

    state = {
        persons: [],
        show: false
    };


    componentDidMount() {
        axios.get('')
            .then(response => {
                const result = response.data.data.slice(0, 5);
                this.setState({persons: result});
            });
    }

    personSelectedHandler = (id) => {
        this.showModal();
    };

    showModal = () => {
        this.setState({ show: true });
    };

    hideModal = () => {
        this.setState({ show: false });
    };

    render() {
        const persons = this.state.persons.map(person => {

            let avatar;
            if (person.picture_id != null) {
                avatar = person.picture_id.pictures["128"];
            }
            return <ListGroup>
                <ListGroup.Item>
                    <Person
                        key={person.id}
                        name={person.name}
                        company={person.org_id.name}
                        first_char={person.first_char}
                        image={avatar}
                        clicked={() => this.personSelectedHandler(person.id)}
                    />
                </ListGroup.Item>
            </ListGroup>
        });

        return (

            <div className="Wrapper">
                <Modal show = {this.state.show} handleClose = {this.hideModal}/>
                <Header/>
                <div className="Breadcrumb">
                    <h4 className="Breadcrumb-text"><b>People's List</b></h4>
                    <hr/>
                </div>
                {persons}
            </div>
        );
    }

}

export default PersonList;

2 个答案:

答案 0 :(得分:1)

onRequest

这将在每次重新渲染父函数时为<Person ... clicked={() => this.personSelectedHandler(person.id)} /> 定义一个新的函数引用。这将导致props.clicked的道具在每次渲染时都发生更改,从而导致Person也重新渲染。

由于您当前不在Person中使用id,因此可以省略参数并保持函数引用不变:

personSelectedHandler

如果您最终需要使用clicked={this.personSelectedHandler} 上下文,那么您可能想考虑使用父母的状态来实现自己所追求的目标,如果您真的想避免的话重新渲染。

您还可以将id转换为(纯)类组件,并从该组件内部处理回调。

最后,如果要推一下推,而您绝对必须使用此嵌入式箭头功能,则可以覆盖Person的比较功能,这与为类组件定义React.memo类似。 From the docs:

componentShouldUpdate

我可能不知道有另一种方法可以完成这项工作,但是希望这可以帮助您了解问题,以探索替代解决方案。这里也有一些想法和讨论:Why shouldn't JSX props use arrow functions or bind?

答案 1 :(得分:1)

如果使用钩子,则可以将v-modeluseCallback()一起使用。 在您的componenet中:

Recat.memo
只要const callBack = useCallback(() => this.personSelectedHandler(person.id),[person.id]); 相同,

useCallback((person.id) => personSelectedHandler(person.id),[person.id]);总是返回相同的函数实例。 然后:

person.id