【问题标题】:ReactJS - passing data between state and propsReactJS - 在状态和道具之间传递数据
【发布时间】:2018-09-05 17:53:50
【问题描述】:

我有两个组件用于获取和呈现数据。我想要做的是在单击时更改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


    【解决方案1】:

    正如您所写,有两个组件(CarCarSearch)试图控制标签。使用 React 的最佳方式是拥有“黄金”事实来源。

    有两种方法可以实现:

    Parent 是搜索组件状态的黄金来源。

    让您的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})
    }
    

    其他提示:

    选择哪一个?

    这取决于组件的职责是什么。例如在搜索时,如果您想在 Car 内的其他组件上反映这一点,例如搜索时禁用 AddCar,则应由 Parent 负责。如果没有,搜索组件可以拥有搜索的状态。

    另一个提示,我建议不要依赖标签来显示,而是保持搜索组件的状态。例如您的搜索可能有许多状态: 首字母|搜索中|搜索失败|搜索成功,有 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
      }
    

    }

    【讨论】:

      【解决方案2】:

      这里,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

      【讨论】:

      • 感谢您的回答 - 我对其进行了测试,问题是现在跳过了 Filtering... 阶段。我还尝试添加setTimeout 以查看脚本是否不是太快,但事实并非如此。 Filtering... 现在完全被跳过了。
      猜你喜欢
      • 1970-01-01
      • 2021-09-06
      • 2017-06-03
      • 2017-11-24
      • 1970-01-01
      • 1970-01-01
      • 2019-04-05
      • 2015-12-02
      • 1970-01-01
      相关资源
      最近更新 更多