【问题标题】:How to prevent navigation to a component when a specific part of state is missing?当状态的特定部分丢失时,如何防止导航到组件?
【发布时间】:2017-12-20 22:49:25
【问题描述】:

首先请原谅措辞不佳的问题。

我有一个 SPA,其中有一个包含此路线的页面:

/students

这个页面的容器是StudentsView.js,在里面我这样做是为了获取学生列表:

  componentDidMount () {
    this.props.actions.loadStudents()
  }

这是一个学生列表,点击一个会根据学生ID进入学生的详细信息页面:

/student/5

这个页面的组件是StudentDetailView.js

现在,为了避免在初始应用程序加载期间进行不必要的 API 调用以提高性能,我没有调度对 loadStudents() 操作的调用,该操作从 API 调用中设置学生状态部分,因为此页面不是我的应用程序。

现在的问题是当用户导航到学生详细信息页面时说:

/student/5

然后刷新页面,因为它们位于不同的组件上,并且不再调用 StudentsView.js 组件的 componentDidMount(),我最终在我的状态下得到一个空的学生数组,所以在我的学生详细信息组件学生将是未定义的:

function mapStateToProps (state, ownProps) {
  const studentId = +ownProps.params.id
  let student = { id: '', firstName: '', lastName: '' }
  if (studentId && state.students.length > 0) {
    student = getStudentById(state.students, studentId)
  }
  return {
    student: student
  }
}

除了确保在初始应用加载中调用 loadStudensts() 操作之外,还有其他解决方法吗?

最佳做法是什么,如果students 的列表为空,我是否将用户导航回列表页面?有没有办法,是否建议我在 StudentDetailView.js 组件中取消 loadStudents() 操作?

基本上,当用户在StudentDetailView.js 上时,我如何确保始终填充学生状态部分?

感谢您的帮助。

【问题讨论】:

    标签: reactjs redux react-router react-redux


    【解决方案1】:

    经过一番思考,我认为现在实现这一目标的最佳方法是在学生详细信息组件上发送loadStudentById() 操作。我可以在 componentDidMount() 内部做到这一点:

      componentDidMount () {
        const studentId = this.props.params.id
        this.props.actions.loadStudentById(studentId)
      }
    

    原来the seed project I'm using 有一种独特的异步加载路由的方法,他们建议不要使用生命周期挂钩来分发操作以检索数据。基本上只有在路由匹配后才加载组件,此时我可以拦截这个钩子并在组件加载之前调度 getStudentById() 操作。比如:

    import { loadStudentById } from '../../actions/studentActions'
    
    export default (store) => ({
      path : 'student/:id',
      getComponent (nextState, cb) {
        require.ensure([], (require) => {
          const studentId = nextState.params.id
          store.dispatch(loadStudentById(studentId))
          const student = require('./components/StudentDetailView').default
          cb(null, student)
        }, 'student')
      }
    })
    

    更多细节在这里:

    Populating a Component On Load

    该项目的创建者采用了一种非常时尚的方法。

    【讨论】:

      【解决方案2】:

      我相信你正在使用 redux,所以在你的 StudentDetail 组件中你可以发送一个动作说loadStudentById(5) 并且在你的动作中你可以检查loadStudents返回的数据是否可用如果没有你可以先@987654323 @ 后跟loadStudent()

      //somewhere in your actions
      function loadStudent(studentId) {
        return (dispatch, getState) => {
          dispatch(loadStudents()).then(() => {
            const students = getState().students.get('students')
            const student = students.find(s => s.id === studentId)
      
            // This action will set the student in reducer when type is matched
            dispatch(setStudent(student))
          })
        }
      }
      

      所以setStudent 可能是这样的

      function setStudent(student) {
        return {
          type: 'SET_STUDENT',
          payload: student
        }
      }
      

      要检查学生是否已经可用并避免在您的 loadStudents 中调用 API,您可以执行类似的操作

      function loadStudents() {
        return (dispatch, getState) => {
          const students = getState().students.get('students')
      
          // Return early avoiding API call
          if (students && students.length > 0) {
            return Promise.resolve()
          }
      
          // actual API loading logic here
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-24
        • 2019-02-20
        • 2020-12-12
        • 2021-06-27
        • 2016-02-23
        相关资源
        最近更新 更多