【问题标题】:react-native with Redux dynamic data sourcereact-native 与 Redux 动态数据源
【发布时间】:2018-06-05 15:17:26
【问题描述】:

我正在使用 Udemy: The Complete React Native and Redux Course by Stephen Grider 学习 RN,并且正在使用 Firebase 创建一个管理应用程序。

我有来自react-redux 库的连接函数和mapStateToProps(),所以每次我的状态发生变化时,我都会在组件中接收它们作为道具。

我创建了一个从 Firebase 数据库获取数据的操作,我将在 componentWillMount() 中调用它,但由于获取数据是一项异步任务,我必须在 componentWillReceiveProps() 中创建我的数据源。

但是教练说我必须在componentWillMount()componentWillReceiveProps() 中都给我的createDataSource() 打电话 .

我不明白为什么!如果我的状态有任何变化(这是我的员工名单),我会将它们作为道具接收,所以我认为只需在 componentWillReceiveProps() 中调用 createDataSource() 就足够了。

有人可以为我声明吗?有没有我忘记处理的特殊情况?

更新

EmployeeActions.js:

export const employeesFetch = () => {
  const { currentUser } = firebase.auth();

  return dispatch => {
    firebase
      .database()
      .ref(`/users/${currentUser.uid}/employees`)
      .on("value", snapshot => {
        dispatch({ type: EMPLOYEES_FETCH_SUCCESS, payload: snapshot.val() });
      });
  };
};

EmployeeList.js:

  componentWillMount() {
    this.props.employeesFetch();

    this.createDataSource(this.props);
  }

  componentWillReceiveProps(nextProps) {
    this.createDataSource(nextProps);
  }

  createDataSource({ employees }) {
    const ds = new ListView.DataSource({
      rowHasChanged: (r1, r2) => r1 !== r2
    });

    this.dataSource = ds.cloneWithRows(employees);
  }

所以我使用 ListView 来展示我从 Firebase 获取的员工!如果我只在componentWillReceiveProps() 中使用createDataSource() 会有什么问题吗?

【问题讨论】:

  • 你能发布一些代码吗?很难理解你的意思。通过阅读你,我会说 A)Reducers 不应该获取数据 B)componentWillReceiveProps(我认为它已被弃用)听起来像你应该使用的方法 C)尝试尽可能多地使用功能组件与 Redux 和 D)用户 redux -thunk 处理异步操作
  • @PabloBarriaUrenda 代码已添加。 A) 是一个错字,我的意思是操作 B) 那么还有其他方法吗?
  • E) 什么是 createDataSource?这是 Firebase 特有的东西吗?
  • 不幸的是,Stephen Grider 在 Udemy 的课程已经过时,以至于现在已经没用了。而且作者已经一年多没有回复用户更新课程的问题了。他使用的许多材料、API、方法、工具在 2019 年现在已经无关紧要了。但我同意,它们在 2017 年和 2018 年初都非常好

标签: javascript reactjs react-native redux react-redux


【解决方案1】:

我也完成了你提到的 Udemy 课程,首先我不得不说,使用 componentWillReceiveProps() 和 componentWillMount() 道具已被弃用,不应再使用。在新项目中,建议您使用静态 getDerivedStateFromProps() 和 componentDidUpdate()。 React 官方文档将为您提供有关此主题的更多信息。

但是 componentWillReceiveProps() 只会在初始渲染完成后调用,所以如果你的组件在实例化时没有收到 props,你需要在 componentWillMount() 中进行设置。

编辑 如果您想遵循新的最佳实践,您可以这样做:

  • 在构造函数中进行任何实例化
  • 异步设置需要进入 componentDidMount()
  • 静态 getDerivedStateFromProps() 在每次渲染之前调用,(由于更新,初始渲染和重新渲染)
  • componentDidUpdate() 在初始渲染后更新 props 时调用

【讨论】:

  • tnx for first part - second part:所以在初始渲染之后(如果我在状态中有更新,所以我将它们作为道具)辅助函数 createDataSource() 将被调用两次?一次是在 componentWillMount() 中,因为我正在导航到那个场景,第二次是在 componentWillReceiveProps() 中,因为我有新的道具!我说的对吗?
  • componentWillMount 在初始渲染之前被调用,但如果您确定组件在其构造函数中接收到最新的数据源,您确实不需要 componentWillMount
  • 实际上不推荐使用 componentWillMount 的原因是因为很多人在这里执行异步操作,这可能会延迟渲染并导致感知性能下降
  • tnx 供您描述 - 我还不明白的一件事是,如果我使用斯蒂芬的方式,我会调用 createDataSource() 两次?
  • 一般只调用一次
【解决方案2】:

我也上过同样的 Udemy 课程,在我读到一些 React 生命周期被弃用并被不同的生命周期取代后,我正在重构代码。

这是我获取和更新的旧逻辑:

    state = { dataSource: [] }

    componentWillMount() {
      const { userCentres } = this.props;

      this.props.fetchCentres(userCentres);
      this.createDataSource(this.props);
    }

    componentWillReceiveProps(nextProps) {
      this.createDataSource(nextProps);
    }

    createDataSource({ centresList }) {
      this.setState({ dataSource: centresList });
    }

我尝试使用static getDerivedStateFromProps 替换我当前的逻辑,但我遇到了问题,因为我无法在其范围内使用关键字this,这意味着我无法从中调用this.createDataSource(props)。我还阅读了“you probably don't need derived state”,然后决定改用getSnapshotBeforeUpdatecomponentDidUpdate 会更好。

getSnapshotBeforeUpdate() 在最近渲染的输出被提交到之前被调用,例如DOM。它使您的组件能够在可能更改之前从 DOM 中捕获一些信息(例如滚动位置)。 此生命周期返回的任何值都将作为参数传递给 componentDidUpdate()

这就是我重构代码的方式:

      state = { dataSource: [] }

      componentDidMount() {
        const { userCentres } = this.props;

        this.props.fetchCentres(userCentres);
      }

      componentDidUpdate(prevProps, prevState, snapshot) {
        if (snapshot) {
          this.createDataSource(this.props);
        }
      }

      getSnapshotBeforeUpdate(prevProps) {
        if (prevProps.centresList !== this.props.centresList) {
          return true;
        }

        return null;
      }

      createDataSource({ centresList }) {
        this.setState({ dataSource: centresList });
      }

即使我不能 100% 确定这是解决问题的最佳方法,这最终对我有用。我还应该注意这是一个 PureComponent。

【讨论】:

    猜你喜欢
    • 2017-05-16
    • 1970-01-01
    • 2021-10-23
    • 2017-05-17
    • 1970-01-01
    • 2021-02-08
    • 2017-11-28
    • 2021-12-14
    • 2018-02-19
    相关资源
    最近更新 更多