我有一个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
代码
答案 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
组件showMultiMatch
和onSearchClose
引入其他道具,并将showSearch
添加到OrderSection
组件(当您收到{ {1}},并在multiMatch
处理程序中设置为false)。删除onSearchClose
并检查render函数中的条件componentWillReceiveProps
以有条件地呈现搜索。