Поддержание нескольких значений состояния в пользовательском крюке реакции

#reactjs #react-hooks

Вопрос:

Я ищу простой способ хранения нескольких простых значений в пользовательском крючке react. Неудобно, когда приходится возвращать множество сеттеров и геттеров. Я мог бы передать по одному значению для каждого, то есть const modalState = useState(false) затем ссылаться на modalState[0] и [1], но это кажется странным. Что мне не нравится в моей функции ниже, так это то, что она возвращает 10 значений. Это кажется многовато.

 function useNotesModal() {
  const [showModal, setShowModal] = useState(false);
  const [modalNoteId, setModalNoteId] = useState(0); // if 0, means create note in modal
  const [modalNoteTitle, setModalNoteTitle] = useState("");
  const [modalNoteDescription, setModalNoteDescription] = useState("");
  const [modalNoteTagIds, setModalNoteTagIds] = useState([]);

  return {
    showModal,
    setShowModal,
    modalNoteId,
    setModalNoteId,
    modalNoteTitle,
    setModalNoteTitle,
    modalNoteDescription,
    setModalNoteDescription,
    modalNoteTagIds,
    setModalNoteTagIds,
  };
}
export default useNotesModal;
 

Комментарии:

1. Я не уверен, что понимаю ваш вопрос. Вы имеете в виду, что хотите иметь, возможно, несколько независимых модалов, использующих хук для хранения их состояния, и состояние каждого модала может иметь несколько полей? Или просто вы не хотите возвращать несколько параметров и значений с крючка?

2. @MattMorgan, я ищу лучший шаблон для подражания, который не был бы безумно сложным с редукторами. Может быть, вычисляемые свойства интегрированы с оператором распространения? Просто кажется, что это плохо масштабируется.

3. Но контекст (что именно является целью) может быть действительно важным, чтобы предложить лучшую альтернативу. Скажем , для этой конкретной структуры я думаю, что передача modalNoteId и т. modalNodeTitle Д. В качестве аргументов хука Может быть намного удобнее, чем возвращаемые сеттеры для каждого из них.

4. @skyboyer, кажется неудобным затем использовать аргументы возврата, такие как: modelNoteId[1](101);

Ответ №1:

Вы можете паковать возвращаемые значения, например, в виде значений и действий:

 function useNotesModal() {
  const [showModal, setShowModal] = useState(false);
  const [modalNoteId, setModalNoteId] = useState(0); // if 0, means create note in modal
  const [modalNoteTitle, setModalNoteTitle] = useState("");
  const [modalNoteDescription, setModalNoteDescription] = useState("");
  const [modalNoteTagIds, setModalNoteTagIds] = useState([]);

  return {
    values: {
      showModal,
      modalNoteId,
      modalNoteTitle,
      modalNoteDescription,
      modalNoteTagIds
    },
    actions: {
      setShowModal,
      setModalNoteId,
      setModalNoteTitle,
      setModalNoteDescription,
      setModalNoteTagIds,
    }
  };
}
 

Другой вариант-автоматически паковать их по value и set :

 const { useState, useEffect } = React;

function useNotesModal() { 
  const states = {
    showModal: useState(false),
    modalNoteId: useState(0),
    modalNoteTitle: useState(""),
    modalNoteDescription: useState(""),
    modalNoteTagIds: useState([])
  }
  
  return Object.fromEntries(
    Object.entries(states)
      .map(([k, [value, set]]) => [k, { value, set }])
  );
}

const Demo = () => {
  const notesState = useNotesModal();
  
  useEffect(() => {
    setTimeout(() => {
      notesState.modalNoteId.set(101);
    }, 2000);
  }, []);
  
  console.log(notesState);
  
  return <div>{notesState.modalNoteId.value}</div>;
}

ReactDOM.render(
  <Demo />,
  root
); 
 <script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>

<div id="root"></div> 

Комментарии:

1. чего бы хотел аналогичный сеттер console.log(notesState); ?

2. Я понимаю, что могу получить значение с помощью xxx.modalNoteId.value, но теперь следуйте инструкциям, как установить значение?

3. Запустите фрагмент и посмотрите на результаты (или в консоли браузера) — notesState. modalNoteId.set .

4. Я попробовал xxx.modalNoteId.set(101) и получил ошибку отправки. Не могли бы вы обновить свой образец, пожалуйста? Это помогло бы.

5. Это работает. Обновил пример. Повторите пример еще раз.

Ответ №2:

Один из возможных подходов состоял бы в том, чтобы просто использовать один объект для сохранения состояния и возвращать задатчик для этого объекта.

Что-то вроде:

 function useNotesModal() {
  const [state, setState] = useState({
    showModal: false,
    modalNoteId: 0,
    modalNoteTitle: "",
    modalNoteDescription: "",
    modalNoteTagIds: [],
  });
  

  function setFieldState(fieldName, value){
    setState({...state, [fieldName]: value});
  }

  return [state, setFieldState];
}

// Then, to use:

const [modalState, setModalState] = useNotesModal();

const showModal = modalState['showModal'];

setModalState("showModal", true);

 

Ключ в этом случае состоит в том, чтобы гарантировать, что вы возвращаете новый объект каждый раз, когда обновляется внутреннее состояние.