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

时间:2018-09-05 17:53:51

标签: reactjs state react-props

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

2 个答案:

答案 0 :(得分: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内的其他组件上反映出来,例如。在搜索时禁用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
  }

}

答案 1 :(得分:0)

在这里,constructor组件的CarSearch方法在挂载后仅被调用一次。再也不会调用它了。因此,当传入的CarSearch道具与您当前的状态不同时,您可以做的是在searchBtnLabel组件和setState中使用componentDidUpdate方法。

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