Это правильный вариант использования для ловушки React useImperativeHandle? - PullRequest
1 голос
/ 13 апреля 2019

Я изучаю перехватчики React (и я довольно новичок в React) и обдумывал варианты использования для useImperativeHandle. Я придумал довольно полезный сценарий.

Я знаю, что это можно сделать без использованияImperativeHandle, но я думаю, что здесь есть некоторые преимущества.

Чего я не знаю ...

  1. Я «обнаружил очевидное», и это не очень полезно? ... или
  2. Это плохая форма или анти-паттерн?

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

У меня есть минимальный пример, размещенный на Github, если вы хотите поиграть с ним: https://github.com/ericsolberg/react-uih-hook

Использование разметки, аналогичной:

const App = props => {
  return (
    <Foo>
      <Bar>This is Bar 0</Bar>
      <Bar>This is Bar 1</Bar>
      <Bar>This is Bar 2</Bar>
    </Foo>
  );
};

То, чего я достиг, это:

  1. Разрешить родительскому компоненту 'Foo' предоставлять хранилище состояний для своих дочерних элементов, поэтому Foo может монтировать / отключать дочерние элементы, но при этом разрешать им восстанавливать состояние.
  2. 'Bar' использует useImperativeHandle для обеспечения 'вызова', чтобы Bar мог наложить вето на демонтаж в случае, если он делает что-то важное.

Как я уже заметил, это работает отлично. В React данные и реквизиты текут по дереву, а обратные вызовы - вверх. Это дает вам возможность для определенных сценариев вызывать дерево. Желательно ли это?

1 Ответ

2 голосов
/ 13 апреля 2019

Это анти-шаблон: Inject props into the children без явной передачи реквизитов.

Идиоматические опции:

Поэтому, если для моей бизнес-логики нет ничего более простого, я делаю что-то вроде следующего, чтобы избежать невидимой жесткой связи между Foo и Bar:

const App = () => (
  <Foo>
    {({selector, saveStateFactory}) => (<>
      <Bar state={selector(0)} saveState={saveStateFactory(0)} />
      <Bar state={selector(1)} saveState={saveStateFactory(1)} />
    </>)}
  </Foo>
)

const Foo = () => {
  const [state, dispatch] = useReducer(...)
  const selector = (id) => state[id]
  const saveStateFactory = (id) => {
    return (payload) => dispatch({type: id, payload})
  }
  // do something with whole state that cannot be done in App nor Bar
  return children({selector, saveStateFactory})
}
...