React路由器在每次更新时都会卸载和重装子组件。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React路由器在每次更新时都会卸载和重装子组件。相关的知识,希望对你有一定的参考价值。

我已经创建了一个组件,这是一个包装器周围的形式组件。

class RestaurantEdit extends React.Component {
  constructor(props) {
    super(props)
    this.state = { waitingForRequest: false }
  }

  componentDidUpdate(prevProps) {
    const { currentRequestState } = this.props
    const { waitingForRequest } = this.state
    if (
      waitingForRequest &&
      prevProps.currentRequestState === requestStates.PENDING &&
      currentRequestState === requestStates.SUCCESS
    ) {
      this.props.history.goBack()
      this.setState({ waitingForRequest: false })
    }
  }

  handleSubmit = (restaurantInfos, restaurantId) => {
    const { editRestaurant } = this.props
    const { password, ...dataWithoutPassword } = restaurantInfos
    this.setState({ waitingForRequest: true })
    if (password === '') {
      editRestaurant(restaurantId, dataWithoutPassword)
    } else {
      editRestaurant(restaurantId, restaurantInfos)
    }
  }

  handleCancel = () => {
    this.props.history.goBack()
  }

  render() {
    const { id, data = {} } = this.props
    const { password, ...dataWithoutPassword } = data
    return (
      <RestaurantForm
        id={id}
        data={dataWithoutPassword}
        onCancel={this.handleCancel}
        onSubmit={this.handleSubmit}
        isPasswordRequired={false}
      />
    )
  }
}

const mapStateToProps = state => ({
  currentRequestState: restaurantSelectors.getRequestState(state)
})

const mapDispatchToProps = dispatch => ({
  editRestaurant: (restaurantId, restaurantInfos) => {
    dispatch(editRestaurantRequested(restaurantId, restaurantInfos))
  }
})

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(RestaurantEdit)

这个组件被挂载在它的父级React router switch中。

    <Switch>
      <Route
        path="/restaurants/new"
        exact
        component={props => (
          <RestaurantCreate onSuccess={this.handleSuccess} {...props} />
        )}
      />
      <Route
        path="/restaurants/edit"
        component={props => {
          const id = props.location.search.split('=')[1]
          const data = currentCityRestaurants.find(resto => resto.id === id)
          return <RestaurantEdit id={id} data={data} {...props} />
        }}
      >
      </Route>
      <Route
        path="/restaurants"
        exact
        component={/* otherComponent */}
      />
    </Switch>

我的大问题是,当我试图调度一个动作时(例如 editRestaurant,这是给 RestaurantEdit 作为道具的mapDispatchToProps),商店正在更新,这将使组件卸载并重新装载。

这种卸载将防止 this.setState({ waitingForRequest: true })componentDidUpdate 完成,以及 waitingForRequest 空穴来风

我注意到,如果我把组件作为一个直接的子代传给了 Route 卸载重装将不会发生。

      <Route
        path="/restaurants/edit"
        exact
      >
        <RestaurantEdit …… />
      </Route>

但我不能使用这个解决方案,因为我需要访问... locationhistory 提供 Route 组件。

所以,当我将组件作为 componentRoute ?

答案

当你想要在路由中渲染一个元素时增加一些功能,你需要使用 render 键词 component

在你的例子中

<Route
    path="/restaurants/edit"
    component={props => {
      const id = props.location.search.split('=')[1]
      const data = currentCityRestaurants.find(resto => resto.id === id)
      return <RestaurantEdit id={id} data={data} {...props} />
    }}
  >

将组件关键字改为render,并使用函数返回修改后的组件。

<Route
    path="/restaurants/edit"
    render={ props => {
      const id = props.location.search.split('=')[1]
      const data = currentCityRestaurants.find(resto => resto.id === id)
      return (<RestaurantEdit id={id} data={data} {...props} />)
    }}
  >

这样就可以方便地进行内联渲染和包装,而不会出现上述不受欢迎的重装。

https:/reacttraining.comreact-routerwebapiRouterender-func。

另一答案

当你在渲染周期中使用匿名函数时,就会发生这种情况。React并不知道你的匿名函数的输出与上次渲染的结果是一样的,这就是为什么组件会卸载和重装。

说到这里,你不需要使用渲染道具函数来获取Route道具的访问权。它们已经作为道具传递给你的组件了。

<Route
  path="/restaurants/edit"
  component={RestaurantEdit}
/>
const RestaurantEdit = (props) => {
  console.log(props.location, props.history)

  return ...
}

以上是关于React路由器在每次更新时都会卸载和重装子组件。的主要内容,如果未能解决你的问题,请参考以下文章

React Hook - 仅在组件卸载时使用效果,而不是在依赖项更新时使用

为啥每次渲染都会调用 `useEffect` 的清理功能?

每次更改页面时都会调用 React useEffect (with []) (React Router)

React 上下文每次使用它时都会返回初始状态 - 尽管 setState

如何从 React 中的父类更新我的子组件状态?

React - 登录到尝试页面后的路由和重定向