React-Redux, соединяющий два отдельных компонента с переключателем

#javascript #reactjs #redux #react-redux

#javascript #reactjs #redux #react-redux

Вопрос:

Я знаю, что это, вероятно, очень простой вопрос, но это скорее вопрос типа «Я не понимаю документы, пожалуйста, помогите мне».

Я пытаюсь соединить два компонента с помощью React-Redux: первый — это боковая панель, а второй — модальный, который должен появляться при нажатии на кнопку на боковой панели. Компоненты не связаны ни в каком родительско-дочернем отношении (кроме root), поэтому я предполагаю, что redux — лучший вариант.

Я прочитал все документы redux (и react-redux), и я понимаю основные концепции redux, но мне трудно понять, как их реализовать в моих компонентах.

По сути, я хочу кнопку на боковой панели, которая переключает сохраненное состояние (достаточно true / false), и в соответствии с этим состоянием модальное будет появляться ( state==true => display:block ) и исчезать с помощью кнопки в modal ( state==false => display:none ) .

Я думаю, мне нужно действие для переключения состояния, например:

 const modalsSlice = createSlice({
    name: 'modals',
    initalState,
    reducers: {
        toggleModal(state, action){
            state = !state;
        }
    }
});
 

затем соединяем действие в обоих компонентах (я пишу компоненты в классах, а не как функции), используя:

 const toggleModal = {type: 'modals/toggleModal', payload: ''};
const mapStateToProps = state => state.showHideModal;

export default connect(mapStateToProps, toggleModal)(Component);
 

Теперь, предполагая, что я пока прав, я не уверен, как продолжить. Т.е. Как я предполагаю получить и внести изменения в сами компоненты? Конечно, мне нужно поместить функцию в кнопку со onClick={foo} слушателем, но как foo предполагается получать и обрабатывать состояние? И я полагаю showHideModal , что нужно где-то инициализировать состояние? В корневом компоненте? При настройке хранилища?

Любая помощь будет высоко оценена.

Ответ №1:

Инициализация состояния

Предполагается, что вы инициализируете состояние showHideModal в самом фрагменте. Более того, он должен быть назван как или showModal или hideModal для лучшей интерпретации того, что делает это состояние.

 
const modalSlice = createSlice({
    name: 'modal',
    initialState: {
      showModal: false,
    },
    reducers: {
      toggleModal(state){
          state.showModal = !state.showModal;
      }
    }
});

export const { toggleModal } = modalSlice.actions;

 

Компонент боковой панели

Обработчик onClick события должен быть передан явно через mapDispatchToProps .

 import { toggleModal } from './modalSlice';

class Sidebar extends Component {
  handleClick = () => {
    const { toggleModal } = this.props;
    toggleModal();
  }

  render() {
    return (
      <div>
        {/* rest of JSX */}
        <button onClick={this.handleClick}>Toggle Modal</button>
        {/* rest of JSX */}
      </div>
    );
  }
}

const mapDispatchToProps = {
  toggleModal,
};

export default connect({}, mapDispatchToProps)(Sidebar);

 

Модальный

Примечание: вы не можете получить доступ к свойству напрямую из состояния, как вы это делали state.showHideModal; . Сначала вам нужно получить доступ к фрагменту, а затем к свойству, присутствующему в нем state.modal.showHideModal; .

 
class Modal extends Component {
  handleClick = () => {
    const { toggleModal } = this.props;
    toggleModal();
  }

  render() {
    const { showModal } = this.props;

    return (
      <>
        {showModal ? (
          <div>
            <button onClick={this.handleClick}>Close</button>
          </div>
        ) : null}
      </>
    );
  }
}

const mapDispatchToProps = {
  toggleModal,
};

const mapStateToProps = state => ({
  showModal: state.modal.showModal,
});

export default connect(mapStateToProps, mapDispatchToProps)(Modal);

 

Обновить

Переходя к причине, по которой Redux выдает следующее предупреждение:

В действии в пути было обнаружено несериализуемое значение: payload

Это потому, что SyntheticEvent передается в качестве полезной нагрузки для действия. Чтобы исправить это, вам нужно переместить toggleModal вызов из функции onClick prop в отдельную функцию-обработчик. Для справки, проверьте handleClick функцию в модальном и боковой панели.

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

1. Во-первых, вам не нужно определять { type, payload } объект, поскольку Redux Toolkit обрабатывает его внутренне с toggleModal помощью action, что ничем mapDispatchToProps не отличается. Во-вторых, я обновил ответ с помощью Modal.js . В-третьих, теперь так работает назначение деструктурирования ES6, пожалуйста, ознакомьтесь с документацией .

2. Абсолютно! Вам не нужно переходить showModal из приложения в модальное, поскольку оно обрабатывается Redux. Просто оберните приложение <Provider /> с помощью хранилища в качестве реквизита, и все готово. Да, порядок деструктурирования не имеет значения, либо вы пишете const { foo, bar } = this.props; , либо const { bar, foo } = this.props; он остается неизменным 🙂

3. Нет, все еще ничего.

4. Хорошо, поэтому я добавил оператор if с alert in в него в редукторе, чтобы увидеть, действительно ли изменяется состояние (вы можете видеть в изолированной среде) — состояние действительно меняется! Это означает, что редуктор работает, но что-то в Modal.js коде не работает.

5. В настоящее время единственный способ, которым я смог заставить его работать, — добавить <Modal> функцию Sidebar рендеринга. Но похоже, что я неправильно использую Redux (или, по крайней мере, не использую его в полной мере), потому что, насколько я понимаю, если я вкладываю <Modal> внутрь Sidebar , нет никакого реального преимущества в использовании store , я могу сделать это с помощью обычного React .