ReactJS-在状态和道具之间传递数据

ReactJS-在状态和道具之间传递数据,reactjs,state,react-props,Reactjs,State,React Props,我有两个用于获取和呈现数据的组件。我想做的是在点击CarSearch组件时更改该按钮的标签(最好是CSS),搜索完成后,我想将基本的“搜索”标签放在那里 但是,当我单击“搜索”按钮并完成搜索时,标签“搜索”未设置,保留在那里的标签仍然是“过滤…”。现在有什么变化 也许我只是把它复杂化了,有更好的方法来实现它 class Car extends Component { constructor() { super(); this.state = {

我有两个用于获取和呈现数据的组件。我想做的是在点击
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>
        )
    }
class汽车扩展组件{
构造函数(){
超级();
此.state={
汽车:[],
searchBtn:'Searchh'
}
}
componentDidMount(){
axios.get(“/api/cars”)
。然后((响应)=>{
this.setState({cars:response.data});
控制台日志('cars:',cars);
}).catch(错误=>{
log('catch IT!->',err);
});
}
handleSearch=()=>{
axios.post('/api/cars/search',searchCars)
。然后(响应=>{
this.setState({cars:response.data,searchBtn:'search'})//但是,此'searchBtn'不会传递给'CarSeach'`
日志('response.data:',response.data);
})
}
render(){
返回(
...
)
}
}
导出默认类CarSearch扩展组件{
建造师(道具){
超级(道具);
searchBtn:props.searchBtnLabel
}
无柄搜索提交(e){
e、 预防默认值();
this.setState({searchBtn:'Filtering…'});
这个.props.onSearch(…)
}
render(){
返回(
…搜索表单。。。
{this.state.searchBtn}
)
}

在这里,
CarSearch
组件的
构造函数
方法在安装后只会被调用一次。它将不再被调用。因此,当传入的
searchBtnLabel
属性与您当前的状态不同时,您可以在
CarSearch
组件中使用方法并设置状态

将以下代码放在
CarSearch
构造函数调用之后

componentDidUpdate(){
if(this.props.searchBtnLabel!==this.state.searchBtn){
this.setState({searchBtn:this.props.searchBtnLabel});
}
}
这会解决你的问题

你在评论中提到过滤阶段没有发生。你可以像

handleSearchSubmit(e){
e、 预防默认值();
this.setState({searchBtn:'筛选…'),()=>{
this.props.onSearch(…);//setTimeout(()=>this.props.onSearch(…),N),其中N是毫秒。
});
}    

说明:
setState
可以接受一个回调函数,一旦状态设置成功就会执行。即使在使用回调函数之后,如果您没有看到过滤文本,您也可以使用我提到的作为注释的
setTimeout

这里,
CarSearch
组件的
构造函数
方法将挂载后只能调用一次。它将永远不会被调用。因此,当传入的
searchBtnLabel
属性与当前状态不同时,您可以在
CarSearch
组件中使用方法并设置状态

将以下代码放在
CarSearch
构造函数调用之后

componentDidUpdate(){
if(this.props.searchBtnLabel!==this.state.searchBtn){
this.setState({searchBtn:this.props.searchBtnLabel});
}
}
这会解决你的问题

你在评论中提到过滤阶段没有发生。你可以像

handleSearchSubmit(e){
e、 预防默认值();
this.setState({searchBtn:'筛选…'),()=>{
this.props.onSearch(…);//setTimeout(()=>this.props.onSearch(…),N),其中N是毫秒。
});
}    

说明:
setState
可以接受一个回调函数,该函数将在状态设置成功后执行。即使在使用回调函数之后,如果您没有看到过滤文本,您也可以使用我提到的作为注释的
setTimeout

正如您所写的,有两个组件(
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>
        )
    }
}
CarSearch
组件处理与搜索相关的一切。 需要考虑的其他提示: 选择哪一个

这取决于组件的责任是什么。对于搜索时的e.x,如果您想在
Car
中的其他组件上反映这一点,对于搜索时禁用AddCar的e.x,则应由父级负责。如果不是,搜索组件可以拥有搜索状态

另一个提示,与其依赖标签来显示,我建议您维护搜索组件的状态。对于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
  }

}正如您所写,有两个组件(
Car
CarSearch
)试图控制标签。使用React的最佳方法是拥有“黄金”真相来源

有两种方法可以实现这一目标:

父级是搜索组件状态的黄金来源。 让你的
C
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})
}
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
  }