React router размонтирует и перемонтирует дочерний компонент при каждом обновлении - PullRequest
0 голосов
/ 22 апреля 2020

Я создал компонент, который является оберткой вокруг компонента формы:

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:

    <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, которому mapDispatchToProps присваивает RestaurantEdit как реквизиты), хранилище обновляется, и компонент отключается и перемонтируется.

Это отключение не позволит завершить this.setState({ waitingForRequest: true }) в componentDidUpdate, а waitingForRequest всегда будет ложным

Я заметил, что если я передам компонент как прямой дочерний элемент Route размонтирование / перемонтирование не произойдет:

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

Но я не могу использовать это решение, так как мне нужен доступ к location и history, предоставляемым компонентом Route.

Так есть ли способ предотвратить все это размонтирование / перемонтирование с маршрутизатором React, когда я передаю компонент как component prop в Route?

Ответы [ 2 ]

1 голос
/ 22 апреля 2020

Если вам нужна дополнительная функциональность при рендеринге элемента в маршруте, вам нужно использовать ключевое слово 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} />
    }}
  >

Изменить ключевое слово компонента для визуализации и использования функции для возврата измененного компонента

<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.com/react-router/web/api/Route/render-func

1 голос
/ 22 апреля 2020

Это то, что происходит, когда вы используете анонимные функции в цикле рендеринга. React не знает, что вывод вашей анонимной функции такой же, как и при последнем рендеринге, поэтому компонент размонтируется и перемонтируется.

С учетом сказанного вам не нужно использовать рендер функция prop, чтобы получить доступ к реквизиту Route. Они уже переданы в качестве реквизита для вашего компонента.

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

  return ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...