ReactJS - 在状态和道具之间传递数据
ReactJS - passing data between state and props
我有两个组件用于获取和呈现数据。我想要做的是在单击 CarSearch
组件时更改该按钮的标签(最好也是 CSS),当搜索完成时,我想把基本的放在那里"Search" 标签。
但是,当我点击搜索按钮并完成搜索时,标签 "Search" 没有设置,而留在那儿的标签仍然是 "Filtering..."。现在有什么变化?
也许我只是把它复杂化了,有更好的方法来实现它。
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>
)
}
这里,CarSearch
组件的constructor
方法在挂载后只会被调用一次。它永远不会再被调用。因此,您可以做的是在 CarSearch
组件中使用 componentDidUpdate
方法,并在传入的 searchBtnLabel
道具与您当前的状态不同时设置状态。
在 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
。
如您所写,有两个组件(Car
和 CarSearch
)试图控制标签。使用 React 的最佳方式是拥有 "Golden" 真实来源。
有两种方法可以实现:
父级是搜索组件状态的黄金来源。
让您的 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>
)
}
}
更改 Car
组件的 onSearch
功能以明确管理搜索状态。
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
内的某些其他组件上反映 e.x。在搜索时禁用 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
}
}
我有两个组件用于获取和呈现数据。我想要做的是在单击 CarSearch
组件时更改该按钮的标签(最好也是 CSS),当搜索完成时,我想把基本的放在那里"Search" 标签。
但是,当我点击搜索按钮并完成搜索时,标签 "Search" 没有设置,而留在那儿的标签仍然是 "Filtering..."。现在有什么变化?
也许我只是把它复杂化了,有更好的方法来实现它。
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>
)
}
这里,CarSearch
组件的constructor
方法在挂载后只会被调用一次。它永远不会再被调用。因此,您可以做的是在 CarSearch
组件中使用 componentDidUpdate
方法,并在传入的 searchBtnLabel
道具与您当前的状态不同时设置状态。
在 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
。
如您所写,有两个组件(Car
和 CarSearch
)试图控制标签。使用 React 的最佳方式是拥有 "Golden" 真实来源。
有两种方法可以实现:
父级是搜索组件状态的黄金来源。
让您的 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>
)
}
}
更改 Car
组件的 onSearch
功能以明确管理搜索状态。
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
内的某些其他组件上反映 e.x。在搜索时禁用 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
}
}