在事件处理程序中使用ReactDOM.render以避免呈现昂贵的组件 [英] Using ReactDOM.render inside an event handler to avoid rendering expensive components

查看:83
本文介绍了在事件处理程序中使用ReactDOM.render以避免呈现昂贵的组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有应用程序列表的React应用程序,每个任务都有截止日期.我希望用户能够单击到期日期以弹出一个日期选择器来选择一个新日期选择器.

I have a React app with a list of tasks which each have due dates. I want the user to be able to click the due date to pop up a datepicker to select a new one.

我正在使用材料UI库 http://www.material-ui .com/#/components/date-picker

I am using the material UI library http://www.material-ui.com/#/components/date-picker

我可以简单地在列表中的每个任务上渲染一个日期选择器,但似乎在长列表中可能会导致性能问题,从而无法在每个项目上渲染如此复杂的组件.我希望只显示截止日期,并且仅在用户单击以更改截止日期时才显示日期选择器.

I could simply render a datepicker on each task in the list but it seems like it might cause performance problems on a long list to render such a complex component on each item. I would prefer to just display the due date and only render the datepicker when the user clicks to change the due date.

这是我想出的解决方案:

Here is the solution I have come up with:

TaskFooter = React.createClass({
    propTypes: {
        task: React.PropTypes.object.isRequired
    },
    onDateChanged(e, newDate){
        // handle data update
    },
    showDatePicker(){
        let dp = ReactDOM.render(
            <MUI.DatePicker autoOk={true} textFieldStyle={{display: 'none'}} onChange={this.onDateChanged} />,
            this.refs.datePickerContainer
        );
        dp.openDialog();
    },
    render() {

        return (
                <div onClick={this.showDatePicker}>
                    <MUI.Libs.SvgIcons.ActionEvent />
                    {this.props.task.duedate}
                    <div ref="datePickerContainer"></div>
                </div>
        );
    }
});

这似乎可行,但是我想知道此模式是否是执行此操作的正确"方法.是否有更好的方法来动态呈现可能昂贵的反应组件以响应事件?

This seems to work, but I want to know if this pattern is the "correct" way to do this. Is there a better way to dynamically render potentially expensive react components in response to an event?

我找到了另一种方法来执行此操作,该方法似乎更具反应性",但是我不确定它是否完全正确.

I have found another way to do this which seems more "react" but I am not sure if it is entirely correct.

TaskFooter = React.createClass({
    propTypes: {
        task: React.PropTypes.object.isRequired
    },
    getInitialState(){
        return {
            showDatePicker: false
        }
    },
    componentDidUpdate(prevProps, prevState){
        if(this.state.showDatePicker && !prevState.showDatePicker){
            this.refs.datePicker.openDialog();
        }
    },
    onDateChanged(e, newDate){
        console.log('new date', newDate);
        this.setState({
            showDatePicker: false
        });
    },
    showDatePicker(){
        this.setState({
            showDatePicker: true
        });
    },
    render() {

        return (
                <div onClick={this.showDatePicker}>
                    <MUI.Libs.SvgIcons.ActionEvent />
                    {this.props.task.duedate}
                    { this.state.showDatePicker ?
                        <MUI.DatePicker autoOk={true} textFieldStyle={{display: 'none'}} onChange={this.onDateChanged} ref="datePicker" />
                    : ''}
                </div>
        );
    }
});

这可以正确显示和隐藏日期选择器,但是在设置关闭状态时,我在控制台中收到以下警告:

This correctly shows and hides the datepicker, but when setting the closed state I get the following warning in my console:

Warning: setState(...): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the DatePickerDialog component.

尽管出现此警告,但状态似乎已在我的组件上正确设置.我应该忽略此警告吗?我的新模式正确吗?

Despite this warning it seem the state is correctly set on my component. Should I ignore this warning? Is my new pattern correct?

推荐答案

在安装React应用时仅使用ReactDOM.render().绝对不能在React组件本身中使用它.

Only use ReactDOM.render() when mounting your React app. It should never be used within a React component itself.

熟悉状态的工作原理.我建议以下内容:

Familiarise yourself with how state works. I suggest the following:

TaskFooter = React.createClass({
    propTypes: {
        task: React.PropTypes.object.isRequired
    },
    getInitialState() {
        return {
            displayDatePicker: false
        };
    }
    onDateChanged(e, newDate) {
        // handle data update
    },
    showDatePicker() {
        this.setState({
            displayDatePicker: false
        });
    }
    componentDidUpdate(prevProps, prevState) {
        // this is a little bit hacky,
        // ideally there would be a prop for DatePicker to instruct it to already be open
        if (this.state.displayDatePicker && !prevState.displayDatePicker) {
            this.refs.dp.openDialog();
        }
    },
    render() {

        return (
            <div onClick={this.showDatePicker}>
                <MUI.Libs.SvgIcons.ActionEvent />
                {this.props.task.duedate}
                {this.state.displayDatePicker ? (
                    <MUI.DatePicker
                        ref="dp"
                        autoOk={true}
                        textFieldStyle={{display: 'none'}}
                        onChange={this.onDateChanged}
                    />
                ) : null}
            </div>
        );
    }
});

这以更清洁的方式实现了相同的目的.状态变量displayDatePicker确定是否显示日期选择器.我还使用了componentDidUpdate()来检测何时启动了日期选择器.

This achieves the same thing in a cleaner fashion. The state variable displayDatePicker determines whether or not the datepicker shows. I've also used componentDidUpdate() to detect when the datepicker has just been activated.

还有一件事.我认为您应该质疑默认情况下显示日期选择器必然会导致性能问题的假设.你知道是这样吗?我担心您可能会为了提高性能而以增加代码复杂度为代价.

One further thing however. I think you should question your assumption that displaying the datepicker by default would necessarily create performance problems. Do you know that to be the case? I fear you might be trading an increase in code complexity for a trivial performance boost.

这篇关于在事件处理程序中使用ReactDOM.render以避免呈现昂贵的组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆