简体   繁体   English

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

[英]React - is it bad practice to pass up a callback?

I have a REACT app which is basically a till for adding items to an order. 我有一个REACT应用程序,基本上是将订单项添加到订单的操作。 I have my OrderSection which does most of the grunt work, including having a barcode scanner, and I have my Search component which is a child of OrderSection, and if someone clicks on a search result it passes that back up to OrderSection via a prop callback. 我的OrderSection可以完成大部分繁琐的工作,包括使用条形码扫描仪,而我的Search组件是OrderSection的子级,如果有人单击搜索结果,它将通过prop回调传递回OrderSection。 。

Now, this is what I initially had, but it had problems: 现在,这是我最初所拥有的,但是有问题:

@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
};

The main issue here is how in OrderSection, in barcodeScanner, when I have multiple matches, I pass them down as a prop into Search, and then Search sees that prop and updates itself in the componentWillReceiveProps function. 这里的主要问题是,当我有多个匹配项时,如何在OrderSection的条形码扫描器中将它们作为道具传递给Search,然后Search看到该道具并在componentWillReceiveProps函数中进行更新。

I wasn't entirely happy with what was happening there -- it was actually fine most of the time, but there was some annoying unexpected behaviour of Search showing itself when the prop actually hadn't changed. 我对那里发生的事情并不完全满意-实际上大多数时候都很好,但是当道具实际上并没有改变时,Search就会表现出一些令人讨厌的意外行为。

So I came up with the idea of passing a callback up from Search to OrderSection: 因此,我想到了将回调从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
};

But I feel like this is probably bad react practice. 但是我觉得这可能是不好的反应习惯。 It's producing the behavior I want but I think if a React expert looks at this they wouldn't like it. 它正在产生我想要的行为,但是我认为如果React专家看了这个,他们会不喜欢它。

Can I get some advice on the proper way to pass search results down to Search to trigger it, while still otherwise allowing the SEARCH element to control its own searchResults code 我可以就将搜索结果传递给Search触发它的正确方法获得一些建议吗,同时仍然允许SEARCH元素控制自己的searchResults代码

You're right in that you shouldn't have to 'intervene' in this way to modify how your state is updated. 没错,您不必以这种方式“干预”来修改状态的更新方式。 You should just set up your state and props and then things should take care of themselves. 您应该只设置自己的状态和道具,然后事情应该自理。

Here are some straightforward approaches that I'd typically use: 以下是我通常使用的一些简单方法:

1) From the OrderSection parent to conditionally render your Search only when there are items: 1)从OrderSection父级仅在存在以下项目时有条件地呈现搜索:

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

2) Within the <Search> child: 2)在<Search>子项中:

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

3) From the OrderSection parent pass in 'isShowing' as a prop: 3)从OrderSection父级传递“ isShowing”作为道具:

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

Then in your Search, extract isShowing from props. 然后在您的搜索中,从道具中提取isShowing

The idea is that you only need to update the state and the rendering should take care of itself. 这个想法是,您只需要更新状态,渲染就可以自己完成。

I would introduce additional props to Search component showMultiMatch and onSearchClose and add showSearch to OrderSection component(which is set to true when you receive multiMatch and set to false in the onSearchClose handler). 我会介绍更多的道具来Search组件showMultiMatchonSearchClose并添加showSearchOrderSection组件(当你收到它设置为true multiMatch ,并在设置为false onSearchClose处理)。 Remove componentWillReceiveProps and check condition this.props.showMultiMatch || this.state.show 删除componentWillReceiveProps并检查条件this.props.showMultiMatch || this.state.show this.props.showMultiMatch || this.state.show in the render function to render search conditionally. 在render函数中的this.props.showMultiMatch || this.state.show可以有条件地渲染搜索。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM