React Flux - 在渲染子组件之前等待道具

时间:2016-11-06 12:11:39

标签: reactjs flux

快速且“简单”:如何在我每次访问父组件(不仅仅是一次)时呈现子组件之前,让我的父组件等待设置某个状态?

更详细一点: 我希望能够根据用户输入过滤结果。我有一个控制器视图“Items”,它调用一个名为“FilterComponent”的子组件,并将过滤器状态作为prop传递。我从控制器向动作创建者进行初始调用,该动作创建者从本地存储中获取保存的过滤器并将它们分派到商店。根据该结果,我更新过滤器状态并将其作为道具传递给孩子。

我遇到困难的是找到一种方法来确保在设置过滤器状态之前我不渲染“FilterComponent”。我可以让它工作,所以当我刷新页面时,它会加载过滤器 - 但是当我访问其他地方的页面并导航到Items控制器时,它就会卡住。

我认为它与我通过action / store获取过滤器的方式有关,在componentDidMount()中调用它 - 因为componentDidMount()只被调用一次而且我需要每次都调用它时间。

import React, { PropTypes } from 'react';
import FilterAction from '../../Actions/FilterActions';
import BaseComponent from '../../Components/Base';
import { Form, FormGroup, FormControl, ControlLabel, InputGroup, DropdownButton, MenuItem, Button } from 'react-bootstrap';
import Select from 'react-select';
import _ from 'lodash';

class FilterComponent extends BaseComponent {
    constructor(props) {
        super(props);

        this.state = {};

        this._bind(
            'handleExperienceChange',
            'handlePriceChange',
            'applyFilter'
        );
    }

    componentDidMount() {
        this.applyFilter();
    }

    handlePriceChange(price) {
        var filter = {};
        var product = this.props.product.tag;

        filter[product] = {
            price: price ? price.value : null
        };

        let updatedState = _.merge(this.state, {
            selectedPrice: price || null
        });

        this.updateFilter(filter);

        this.setState(updatedState);
    }

    getPrice() {
        var price = this.props.lang.select.prices;
        var priceSelect = [];

        Object.keys(price).map(function (key) {
            priceSelect.push({
                value: key,
                label: price[key]
            });
        });

        return priceSelect;
    }

    applyFilter() {
        var filters = this.props.filters || null;
        var product = this.props.product || null;

        if (filters && product && filters[product.tag]) {
            var selectedPrice = filter.price ? {
                value: filter.price,
                label: this.props.lang.select.prices[filter.price]
            } : false;
        }

        var updatedState = {
            selectedPrice: selectedPrice || false
        };
        this.setState(_.merge(this.state, updatedState));
    }

    updateFilter(filter) {
        FilterAction.update(filter);
    }

    render() {
        const { product, lang } = this.props;

        return (
            <div className="filter">
                <div className="flex">
                    <div className="pane-50">
                        <Select  name="price"
                                 placeholder={lang.general.form.input.price}
                                 value={this.state.selectedPrice}
                                 options={this.getPrice()}
                                 onChange={this.handlePriceChange}
                                 searchable={false} />
                    </div>
                </div>
            </div>
        );
    }
}

export default FilterComponent;

2 个答案:

答案 0 :(得分:1)

你有任何错误吗?您filter中的变量applyFilter()似乎未定义。

此外,虽然不相关,但您可以通过使用新密钥和值调用setState()来设置状态,而不必创建整个新状态:

而不是:

var updatedState = {
    selectedPrice: selectedPrice || false
};
this.setState(_.merge(this.state, updatedState));

您可以这样做:

this.setState({
    selectedPrice: selectedPrice || false
});

最后,考虑从applyFilter()调用componentWillMount(),因为它会影响组件的呈现方式。在componentWillMount()之前调用render()

要获得更快的帮助,请考虑在codepen或类似服务上创建项目的简化,隔离但有效的示例。

答案 1 :(得分:1)

如果你的状态还没有准备好,只需从render()方法返回null。每当更新state或props时,render()将再次运行。状态准备就绪后,正常返回子组件。

render() {
    const { product, lang } = this.props;

    if (!this.state.selectedPrice)
      return null;

    return (
        <div className="filter">
            <div className="flex">
                <div className="pane-50">
                    <Select  name="price"
                             placeholder={lang.general.form.input.price}
                             value={this.state.selectedPrice}
                             options={this.getPrice()}
                             onChange={this.handlePriceChange}
                             searchable={false} />
                </div>
            </div>
        </div>
    );
}