Обрабатывать useReducer при переходе от props

Я пытаюсь переопределить использование useReducer в компоненте для конкретных случаев использования.

Следуя моему упрощенному рабочему режиму работы overfly:

function defaultToggleReducer (state, action) {
  console.info('Default toggler used')
  return !state
}

function customTogglerReducer (state, action) {
  console.info('Custom toggler used')
  return !state
}

// Dummy wrap to log the initialization from `Togller` component to point the twice initializations
function toggleInitializer (state) {
  console.info('toggleInitializer')
  return state
}

function Toggler (props) {
  const [
    toggleState,
    toggleDispatch,
  ] = React.useReducer(defaultToggleReducer, false, toggleInitializer)
  
  // Here is the prt making the previous `useReducer` useless
  const state = props.toggleState !== undefined ? props.toggleState : toggleState
  const dispatch = props.toggleDispatch || toggleDispatch
  
  return (
    <button
      type = "button"
      onClick = {() => dispatch({ type: 'add' })}>
      {Boolean(state).toString()}
    </button>
  )
}

function App () {
  const [customToggleState, customToggleDispatch] = React.useReducer(
    customTogglerReducer,
    false
  )

  return (
    <div>
      <fieldset>
        <legend>Default</legend>
        <Toggler />
      </fieldset>
      <fieldset>
        <legend>Customized</legend>
        <Toggler
          toggleState = {customToggleState}
          toggleDispatch = {customToggleDispatch} />
        <button
          type = "button"
          onClick = {() => customToggleDispatch({ type: 'parentAction' })}>
          This is why I want dispatch
        </button>
      </fieldset>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src = "https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src = "https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id = "root" />

Здесь что-то плохо пахнет, я не сомневаюсь, что это работает, но тот факт, что useReducer вызывается в Toggler, даже если не используется, вызывает у меня подозрения. Так что, я думаю, это мертвый редуктор.

Итак, мой вопрос:

Был ли у вас способ правильно получить управление reduce из родительского компонента (по крайней мере: лучше, чем это)?

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
0
28
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Воспользуйтесь составом компонентов, чтобы решить эту проблему. Разбейте Toggler на два компонента - тупой Toggler, который ожидает внешний редуктор, и DefaultToggler, который отображает Toggler и поставляет редуктор.

Если вам нужен стандартный переключатель, используйте DefaultToggler, а если вам нужна специальная версия, используйте тупой Toggler и предоставьте собственный редуктор.

function defaultToggleReducer (state, action) {
  console.info('Default toggler used')
  return !state
}

function customTogglerReducer (state, action) {
  console.info('Custom toggler used')
  return !state
}

// Dummy wrap to log the initialization from `Togller` component to point the twice initializations
function toggleInitializer (state) {
  console.info('toggleInitializer')
  return state
}

function Toggler ({ toggleState: state, toggleDispatch: dispatch }) {  
  return (
    <button
      type = "button"
      onClick = {() => dispatch({ type: 'add' })}>
      {Boolean(state).toString()}
    </button>
  )
}

function DefaultToggler () {
  const [
    toggleState,
    toggleDispatch,
  ] = React.useReducer(defaultToggleReducer, false, toggleInitializer)

  return (
    <Toggler 
      toggleState = {toggleState} 
      toggleDispatch = {toggleDispatch} 
      />
  );
};

function App () {
  const [customToggleState, customToggleDispatch] = React.useReducer(
    customTogglerReducer,
    false
  )

  return (
    <div>
      <fieldset>
        <legend>Default</legend>
        <DefaultToggler />
      </fieldset>
      <fieldset>
        <legend>Customized</legend>
        <Toggler
          toggleState = {customToggleState}
          toggleDispatch = {customToggleDispatch} />
        <button
          type = "button"
          onClick = {() => customToggleDispatch({ type: 'parentAction' })}>
          This is why I want dispatch
        </button>
      </fieldset>
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
<script crossorigin src = "https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src = "https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id = "root" />

О да, в этом есть смысл! Я думал о переносе в сложном контексте, а затем использовать Consumer blabla ... но это проще. Спасибо !

HollyPony 09.04.2021 15:28

Пожалуйста. Если включение некоторых функций в состав компонента усложняет использование, извлеките функциональные возможности в другой компонент или в настраиваемую ловушку и используйте композицию. Контекст обычно хорош как своего рода внедрение зависимостей и позволяет избежать детализации, чего здесь нет.

Ori Drori 09.04.2021 15:30

Да, поэтому я не слишком много исследую таким образом. Примечание: композиция была (и до сих пор) в ключевом слове, я был уверен в этом, это именно то, что я искал :) К вашему сведению: Моя последняя работа включает ToggleBuilder с различными компонентами (конечно, это не компонент Toggle, а скорее Accordion с дизайн безумные особенности) Еще раз спасибо!

HollyPony 09.04.2021 15:40

Другие вопросы по теме

Предупреждение: невозможно обновить компонент при визуализации другого компонента. ReactRedux.Consumer
Почему не работает мемоизация вызова функционального компонента React с помощью хука useMemo ()?
Я хочу использовать перехватчик реакции useState, чтобы сохранить информацию, полученную из API, и отобразить ее на экране. Но я не могу использовать в классе, что я могу сделать?
Сохранение ранее выбранного состояния элемента в шаговом режиме
Как мне связать два объекта firebase как вложенные объекты, а затем продолжить отправку данных на него?
Как получить ошибку машинописного текста при использовании необъявленных полей в диспетчере useState
Сравнение структуры данных firestore с учетом запроса на групповой сбор
Состояние (хуки React-Select) не меняется при обработке пропов React-Select onChange
Как я могу передавать данные от одного компонента к другому с помощью хуков
Как получить выбранное значение из ввода выбора в React