Как иметь несколько провайдеров или состояние, доступное только для части макета

Я следовал руководству по React-Router Modal, чтобы получить что-то похожее 2 DOM (один для модального с текущим местоположением и по умолчанию с предыдущим местоположением).

Проблема: мне нужно иметь возможность передавать через все компоненты в модальный новый реквизит isModal=true, но я не хочу передавать его для всех дочерних и дочерних компонентов.

Мое решение?? Используйте React-Redux для передачи реквизитов isModal только для страницы Modal. (ОБНОВЛЕНИЕ: Похоже, с Redux это невозможно, у меня есть другое решение)

Из Redux-Provider я знаю, что у меня может быть только одно хранилище, но могу ли я обрабатывать несколько поставщиков и хранить дочерние элементы для разных компонентов?

index.js

ReactDOM.render(
  <Provider store={store}>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </Provider>,
  document.getElementById('root')
);

App.js

render() {
  return [
    <Layout key="document-layout" {...this.props}>
      <Page {...{ ...this.props, location: isModal ? previousLocation : location}} />
    </Layout>,
    isModal
    ? <ModalLayout key="modal-layout">
        <Provider store={{...store, isModal:true}}>
          <Page {...this.props} />
        </Provider>
      </ModalLayout>
    : null
  ];
}

Но на модальных страницах mapStateToProps state.isModal никогда не определяется :/


person Arthur    schedule 04.08.2019    source источник
comment
Я только что увидел, что store содержит объект Redux (с отправкой, getState, ..), а не окончательный state, доступный с функцией connect(). Так что мой код не может работать таким образом. У меня есть решение для этого?   -  person Arthur    schedule 05.08.2019


Ответы (1)


Итак, если вы хотите использовать какое-то глобальное состояние типа, я бы использовал новый контекст в последней реакции, например...

...
React.useContext(SomeContext)
...

Узнайте больше здесь, как вы можете использовать его и создать с его помощью приложение в стиле Redux, если хотите.

Это хорошее чтение, НО СТОП....!!!!!!!!

Я бы тоже не стал использовать это, чтобы делать то, что вы хотите. На самом деле ваш URL-адрес (должен) быть глобальным состоянием, и он должен содержать все, что вам нужно, чтобы иногда показывать, что означает рефакторинг структуры ваших URL-адресов и страниц. В этом примере они передают модель true через состояние var, я стараюсь избегать передачи состояния через вызовы URL-ссылки, потому что, если пользователь затем обновляет страницу по этому URL-адресу, состояние теряется, и в этом примере есть явная ошибка при этом. Вот как я мог бы добиться того же, но используя URL-адрес в качестве короля.

import React, { Component } from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

class ModalSwitch extends Component {

  render() {
    return (
      <div>
        <Switch>
          <Route exact path="/" component={Home} />
          <Route path="/gallery/:type?/:id?" component={Gallery} />
          <Route path="/featured/img/:id" component={ImageView} />
        </Switch>
        <Route path="/gallery/img/:id" component={Modal} />
      </div>
    );
  }
}

const IMAGES = [
  { id: 0, title: "Dark Orchid", color: "DarkOrchid" },
  { id: 1, title: "Lime Green", color: "LimeGreen" },
  { id: 2, title: "Tomato", color: "Tomato" },
  { id: 3, title: "Seven Ate Nine", color: "#789" },
  { id: 4, title: "Crimson", color: "Crimson" }
];

function Thumbnail({ color }) {
  return (
    <div
      style={{
        width: 50,
        height: 50,
        background: color
      }}
    />
  );
}

function Image({ color }) {
  return (
    <div
      style={{
        width: "100%",
        height: 400,
        background: color
      }}
    />
  );
}

function Home() {
  return (
    <div>
      <Link to="/gallery">Visit the Gallery</Link>
      <h2>Featured Images</h2>
      <ul>
        <li>
          <Link to="/featured/img/2">Tomato</Link>
        </li>
        <li>
          <Link to="/featured/img/4">Crimson</Link>
        </li>
      </ul>
    </div>
  );
}

function Gallery() {
  return (
    <div>
      {IMAGES.map(i => (
        <Link
          key={i.id}
          to={{
            pathname: `/gallery/img/${i.id}`
          }}
        >
          <Thumbnail color={i.color} />
          <p>{i.title}</p>
        </Link>
      ))}
    </div>
  );
}

function ImageView({ match }) {
  let image = IMAGES[parseInt(match.params.id, 10)];

  if (!image) return <div>Image not found</div>;

  return (
    <div>
      <h1>{image.title}</h1>
      <Image color={image.color} />
    </div>
  );
}

function Modal({ match, history }) {
  let image = IMAGES[parseInt(match.params.id, 10)];

  if (!image) return null;

  let back = e => {
    e.stopPropagation();
    history.goBack();
  };

  return (
    <div
      onClick={back}
      style={{
        position: "absolute",
        top: 0,
        left: 0,
        bottom: 0,
        right: 0,
        background: "rgba(0, 0, 0, 0.15)"
      }}
    >
      <div
        className="modal"
        style={{
          position: "absolute",
          background: "#fff",
          top: 25,
          left: "10%",
          right: "10%",
          padding: 15,
          border: "2px solid #444"
        }}
      >
        <h1>{image.title}</h1>
        <Image color={image.color} />
        <button type="button" onClick={back}>
          Close
        </button>
      </div>
    </div>
  );
}

function ModalGallery() {
  return (
    <Router>
      <Route component={ModalSwitch} />
    </Router>
  );
}

export default ModalGallery;

Это гораздо более простой способ. Ключевым моментом здесь является использование переменных в пути маршрута.

Когда мы посещаем /gallery, мы удовлетворяем путь к галерее, поскольку мы сказали, что :type и :id являются необязательными для этого представления.

Поэтому, когда мы добавляем /gallery/img/0, мы говорим, что это модель, так как мы хотим разместить ее над галереей, и поэтому мы показываем компоненты галереи и модальные компоненты вместе.

Но когда мы перейдем к /featured/img/0, это удовлетворит только ImageView

<Switch>
   <Route exact path="/" component={Home} />
   <Route path="/gallery/:type?/:id?" component={Gallery} />
   <Route path="/featured/img/:id" component={ImageView} />
</Switch>
<Route path="/gallery/img/:id" component={Modal} />
person Ben Smith    schedule 05.08.2019
comment
Я понимаю вашу точку зрения, но вы не отвечаете на мой вопрос, вы просто удаляете точку. Я знаю, что «url» должен быть связан с текущим состоянием. Но, как и в галерее Fb, я хочу иметь возможность различать запрос на модальной странице или на новой странице URL. Пример: я дома / и хочу отобразить /login в модальном окне. Я буду отображать / в фоновом режиме как предыдущее, а /login в модальном окне как текущее. Если пользовательское обновление /login теперь является текущим (и не требуется как модальное), поэтому отображайте его непосредственно в макете по умолчанию в качестве текущего URL-адреса. - person Arthur; 05.08.2019
comment
Или официальный пример React Router неверен? Потому что это то, что они делают :/ - person Arthur; 05.08.2019
comment
Также обратите внимание, что каждый URL-адрес должен работать в модальном режиме и в макете по умолчанию, поэтому с вашим решением я должен удвоить все свои маршруты. - person Arthur; 05.08.2019
comment
хорошо, но избыточность по-прежнему не является хорошим решением этой проблемы, поскольку вы обнаружили, что у вас не может быть провайдера внутри провайдера. У вас может быть много контекстов реагирования, так что, возможно, это правильное решение в этом случае. - person Ben Smith; 05.08.2019