React-传递回调是不好的做法吗?

时间:2019-06-11 12:12:08

标签: javascript reactjs

我有一个REACT应用程序,它基本上是一个向订单添加项目的工具。我的OrderSection可以完成大部分繁琐的工作,包括使用条形码扫描仪,而我的Search组件是OrderSection的子组件,如果有人单击搜索结果,它将通过通过prop回调备份到OrderSection。

现在,这是我最初所拥有的,但是它有问题:

@autobind
class OrderSection extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            orderItems: [],
            multiMatch: [],
        };
    }

    async barcodeScanner(barcode) {
        let response;
        try {
            response = await serverApi.getItemsFromBarcode(barcode);
        } catch(e) {
            return toast.error(e.message || e.toString());
        }

        let {items} = response;

        if (items.length === 0) {
            toast.info('no matching items found');
        } else if (items.length === 1) {
            this.addItem(items[0]);
        } else {
            // show results in the 'search' section
            this.setState({multiMatch: items})
        }
    }

    addItem(item) {
        // doesn't really matter what happens here
    }

    async lookupAdd(no, code) {
        try {
            let {items} = await serverApi.getItems(no, code);
            let item = items[0];
            if (item) {
                this.addItem(item);
            } else {
            }
        } catch(e) {
            toast.error(e.toString());
        }
    }

    render() {
        return (
            <section>
                // render items up here

                <Search  
                    onItemClick={this.lookupAdd} 
                    results={this.state.multiMatch} />
            </section>
        )
    }
}



@autobind
class Search extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            searchResults: [],
            show: false // change to true to show the search
        }
    }

    // code for updating search results on form submit
    // updating this.state.searchResults

    render() {
        return (
            <React.Fragment>
                // form with search text input here
                // render searchResults here
            </React.Fragment>
        )
    }

    componentWillReceiveProps(props) {
        if (props.results.length) {
            this.setState({searchResults: props.results, show: true});
        }
    }
}

Search.propTypes = {
    onItemClick: PropTypes.func.isRequired,
    results: PropTypes.array
};

这里的主要问题是,当我有多个匹配项时,如何在OrderSection的条形码扫描器中将它们作为道具传递给Search,然后Search看到该道具并在componentWillReceiveProps函数中进行自我更新。 / p>

我对那里发生的事情并不完全满意-实际上大多数时候都很好,但是当道具实际上没有变化时,Search就会出现一些令人讨厌的意外行为,从而显示出来。

所以我想到了将回调从Search传递到OrderSection的想法:

@autobind
class OrderSection extends React.Component {

    constructor(props) {
        super(props);
        this.state = {
            orderItems: []
        };
    }

    async barcodeScanner(barcode) {
        let response;
        try {
            response = await serverApi.getItemsFromBarcode(barcode);
        } catch(e) {
            return toast.error(e.message || e.toString());
        }

        let {items} = response;

        if (items.length === 0) {
            toast.info('no matching items found');
        } else if (items.length === 1) {
            this.addItem(items[0]);
        } else {
            // show results in the 'search' section
            this.sendMultiMatchToSearch(items);
        }
    }

    setSearchResultsFunc(func) {
        this.sendMultiMatchToSearch = func;
    }

    addItem(item) {
        // doesn't really matter what happens here
    }

    async lookupAdd(no, code) {
        try {
            let {items} = await serverApi.getItems(no, code);
            let item = items[0];
            if (item) {
                this.addItem(item);
            } else {
            }
        } catch(e) {
            toast.error(e.toString());
        }
    }

    render() {
        return (
            <section>
                // render items up here

                <Search
                    onItemClick={this.lookupAdd}
                    manuallySetResultsFunc={this.setSearchResultsFunc}
                     />
            </section>
        )
    }
}



@autobind
class Search extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            searchResults: [],
            show: false // change to true to show the search
        };

        if (typeof this.props.manuallySetResultsFunc === "function") {
            const func = (results) => {
                this.setState({searchResults: results, show: true});
                this.flash();
            };
            this.props.manuallySetResultsFunc(func);
        }
    }

    render() {
        return (
            <React.Fragment>
                // render searchResults here
            </React.Fragment>
        )
    }
}

Search.propTypes = {
    onItemClick: PropTypes.func.isRequired,
    manuallySetResultsFunc: PropTypes.func
};

但是我觉得这可能是不好的反应习惯。它正在产生我想要的行为,但是我认为如果React专家看了这个,他们会不喜欢它的。

我能否就将搜索结果传递给Search触发它的正确方法获得一些建议,同时仍然允许SEARCH元素控制自己的searchResults代码

2 个答案:

答案 0 :(得分:0)

您是对的,您不必以这种方式“干预”来修改状态的更新方式。您应该先设置自己的状态和道具,然后事情就应该照顾好自己。

以下是我通常会使用的一些简单方法:

1)从OrderSection父级,仅在存在以下项目时有条件地呈现您的搜索:

render() {
        return (
            <section>
                {this.state.multiMatch && <Search
                    onItemClick={this.lookupAdd}
                    manuallySetResultsFunc={this.setSearchResultsFunc}
                     />}
            </section>
        )
    }

2)在<Search>子对象中:

render() {
        return (
            <React.Fragment>
                {this.state.searchResults && this.state.searchResults.map(result=> // map to SearchResults)}
            </React.Fragment>
        )
    }

3)从OrderSection父级传递“ isShowing”作为道具:

render() {
        const isShowing = !!this.state.multiMatch; // add other logic here if necessary
        return (
            <section>
                 <Search
                    onItemClick={this.lookupAdd}
                    isShowing={isShowing}
                     />
            </section>
        )
    }

然后在搜索中,从道具中提取isShowing

这个想法是,您只需要更新状态,渲染就可以自己完成。

答案 1 :(得分:0)

我会向Search组件showMultiMatchonSearchClose引入其他道具,并将showSearch添加到OrderSection组件(当您收到{ {1}},并在multiMatch处理程序中设置为false)。删除onSearchClose并检查render函数中的条件componentWillReceiveProps以有条件地呈现搜索。