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

如您所写,有两个组件(CarCarSearch)试图控制标签。使用 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
  }

}