TLDR; CodeSandbox Demo
Хорошо, после небольшой работы я нашел метод решения проблемы (я новичок в React), так что, возможно, это глупое решение.Если да, предоставьте лучший ответ, и я с радостью приму ваш ответ.
Решение
Использование библиотеки Unstated ,Я могу создать оболочку вокруг React Context API, которая обеспечивает внедрение зависимостей.Это позволяет мне создавать экземпляры, которые я могу передать своим компонентам.
Например:
import { Provider, Subscribe } from "unstated";
import CounterContainer from "./counter";
let counterA = new CounterContainer({ initAmount: 4 });
let counterB = new CounterContainer({ initAmount: 8 });
const Red = () => {
return (
<Subscribe to={[CounterContainer]}>
{counter => (
<div className="red">
<span>{counter.state.count}</span>
...
</div>
)}
</Subscribe>
);
};
const App = () => (
<div>
<Provider inject={[counterA]}>
<Red />
</Provider>
<hr />
<Provider inject={[counterB]}>
<Red />
</Provider>
</div>
);
Попробуйте демо-версию на CodeSandbox: https://codesandbox.io/s/k3v3wnzrn7
Обертывание React/ Неустановленный контекст как услуга
Я расширил эту идею и создал скелетную службу API.Служба API содержит свойства состояния, такие как loggedIn
, а также методы обслуживания, такие как login()
и logout()
.Эти свойства и методы доступны во всем приложении с одним импортом в каждое место, где я хочу использовать службу API.
Я сделал это, поместив Unstated Provider, Subscribe and Instance в службу Api.js
.
Например:
Api.js:
import { Provider, Subscribe, Container } from "unstated";
class APIContainer extends Container {
constructor(props = {}) {
super();
this.state = {
loggedIn: false
};
}
async login() {
console.log("Logging in");
this.setState({ loggedIn: true });
}
async logout() {
console.log("Logging out");
this.setState({ loggedIn: false });
}
}
const Api = {
Instance: new APIContainer(),
Provider,
Subscribe
};
export default Api;
Теперь я могу включить Api.js
в любой другой файл в качестве поставщика,впрыскивая экземпляр, который меня волнует.В этом случае есть только один экземпляр, но я могу предоставить другой экземпляр, если я хочу запустить параллельные тесты.
App.js:
import Api from "./Api";
class App extends React.Component {
render() {
return (
<div>
<Api.Provider inject={[Api.Instance]}>
<Routes />
</Api.Provider>
</div>
);
}
}
render(<App />, document.getElementById("root"));
ТогдаЯ могу включить в приложение Api.js
и подписаться на то, какой экземпляр был передан по дереву.
Pages / Foo.js:
import Api from "../Api";
class Foo extends React.Component {
render() {
return (
{api => (
? Foo
api.state.loggedIn = {api.state.loggedIn ? "? true" : "? false"}
api.login ()}> Login api.logout ()}> Logout )});}} экспорт по умолчанию Foo;
Попробуйте демо-версию CodeSandbox здесь: https://codesandbox.io/s/wqpr1o6w15
Возможно, более опытные разработчики React могут понять, насколько я истребляю React Framework без всякой причины) ...