我有两个用于获取和呈现数据的组件。我想做的是单击CarSearch
组件时单击该按钮,并在完成搜索后更改该按钮的标签(最好是CSS),我想在其中放置基本的“搜索”标签
但是,当我单击搜索按钮并完成搜索时,未设置标签“搜索”,并且停留在此处的标签仍为“正在过滤...”。现在正在发生什么变化?
也许我只是把它复杂化了,有一种更好的方法来实现它。
class Car extends Component {
constructor() {
super();
this.state = {
cars: [],
searchBtn: 'Searchh'
}
}
componentDidMount() {
axios.get('/api/cars')
.then((response) => {
this.setState({cars: response.data});
console.log('cars: ', cars);
}).catch(err => {
console.log('CAUGHT IT! -> ', err);
});
}
handleSearch = () => {
axios.post('/api/cars/search', searchCars)
.then(response => {
this.setState({cars: response.data, searchBtn: 'Seach'}) // however, this `searchBtn` will not be passed to `CarSeach`
console.log('response.data: ', response.data);
})
}
render() {
return (
...
<CarAddNew />
<CarSearch
onSearch={this.handleSearch}
searchBtnLabel={this.state.searchBtn}
/>
<CarList cars={this.state.cars} />
)
}
}
export default class CarSearch extends Component {
constructor(props){
super(props);
searchBtn: props.searchBtnLabel
}
handleSearchSubmit(e) {
e.preventDefault();
this.setState({ searchBtn: 'Filtering...'});
this.props.onSearch(...)
}
render() {
return(
... search form ...
<button type="submit" className="btn btn-primary btn-sm mx-sm-2">
{this.state.searchBtn}
</button>
)
}
答案 0 :(得分:2)
正如您所写,有两个组件(Car
和CarSearch
)试图控制标签。使用React的最好方法是拥有“金色”的事实来源。
有两种方法可以实现它:
让您的CarSearch
渲染从Car
传递给它的标签。您甚至可以使CarSearch组件变为无状态。
export default class CarSearch extends Component {
handleSearchSubmit(e) {
e.preventDefault();
this.props.onSearch(...)
}
render() {
return(
... search form ...
<button type="submit" className="btn btn-primary btn-sm mx-sm-2">
{this.props.searchBtnLabel}
</button>
)
}
}
更改onSearch
组件的Car
功能以显式管理搜索状态。
handleSearch = () => {
this.setState({searchBtn: 'Filtering...'});
axios.post('/api/cars/search', searchCars)
.then(response => {
this.setState({cars: response.data, searchBtn: 'Search'})
console.log('response.data: ', response.data);
})
}
CarSearch
组件处理与搜索相关的所有事情。export default class CarSearch extends Component {
handleSearchSubmit(e) {
e.preventDefault();
this.setState({searchBtn: 'Filtering...'});
axios.post('/api/cars/search', searchCars)
.then(response => {
this.setState({searchBtn: 'Search'});
this.props.onSearch(response.data);
})
}
}
render() {
return(
... search form ...
<button type="submit" className="btn btn-primary btn-sm mx-sm-2">
{this.state.searchBtn}
</button>
)
}
}
然后在您的父组件中:
handleSearch = (data) => {
this.setState({cars: data})
}
选择哪一个?
这取决于组件的职责。对于e.x.搜索时,如果要在Car
内的其他组件上反映出来,例如。在搜索时禁用AddCar,则Parent应该负责。如果没有,则搜索组件可以拥有搜索状态。
另一个提示,我建议不要依赖标签来显示,而是建议维护搜索组件的状态。对于e.x.您的搜索可能具有许多状态: 首字母|搜索|搜索失败|搜索成功,共有0条记录|搜索成功,超过0条记录。
明确显示搜索状态,使您可以以更加可预测的模式控制渲染。
class CarSearch extends Component {
state: {
searchState: 'Initial',
searchTerm: ''
}
onSearch () => {
this.setState({searchState: 'Searching'})
axios.post(---)
.then(this.setState({searchState: 'Success'}))
.catch(this.setState({searchState: 'Error'}))
}
render() {
// change styles, conditional rendering, show toast etc. based on the state
}
}
答案 1 :(得分:0)
在这里,constructor
组件的CarSearch
方法在挂载后仅被调用一次。再也不会调用它了。因此,当传入的CarSearch
道具与您当前的状态不同时,您可以做的是在searchBtnLabel
组件和setState中使用componentDidUpdate
方法。
在CarSearch
构造函数调用之后放入以下代码。
componentDidUpdate() {
if (this.props.searchBtnLabel !== this.state.searchBtn) {
this.setState({ searchBtn: this.props.searchBtnLabel });
}
}
这将解决您的问题。
您在评论中提到过滤阶段没有发生。您可以修复它,
handleSearchSubmit(e) {
e.preventDefault();
this.setState({ searchBtn: 'Filtering...'}, () => {
this.props.onSearch(...); // setTimeout(() => this.props.onSearch(...), N) where N is milliseconds.
});
}
说明:setState
可以接受一个回调函数,该函数将在状态成功设置后执行。即使在使用回调之后,如果看不到“正在过滤文本”,也可以使用我提到的setTimeout
作为注释。