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

问题描述 投票:0回答:2

我有两个用于获取和渲染数据的组件。我想要做的是在点击时更改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>
        )
    }
reactjs state react-props
2个回答
2
投票

正如你所写,有两个组件(CarCarSearch)试图控制标签。使用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中的其他组件上反映出来,那么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
  }

}


0
投票

在这里,constructor组件的CarSearch方法在安装后只会被调用一次。永远不会再被召唤。所以,你可以做的是在componentDidUpdate组件中使用CarSearch方法,并且当传入的searchBtnLabel prop与你现在的状态不同时使用setState。

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作为注释。

© www.soinside.com 2019 - 2024. All rights reserved.