For whatever reason, I thought today lets give it a try and see whether I can make the Aurelia Store plugin work with a React app and turns out it works quite well (https://github.com/zewa666/react-aurelia-store):
npx create-react-app my-app --typescript
npm install aurelia-store aurelia-pal aurelia-pal-browser
- Initialize pal in App.tsx
import React from 'react';
import { initialize } from "aurelia-pal-browser";
import './App.css';
import { FrameworkList } from './components/FrameworkList';
import { NewFramework } from './components/NewFramework';
initialize();
const App: React.FC = () => {
return (
<div className="App">
<header className="App-header">
<NewFramework></NewFramework>
<FrameworkList></FrameworkList>
</header>
</div>
);
}
export default App;
And here are my two components.
// FrameworkList.tsx
import React from 'react';
import { useStore } from "../store/state";
export const FrameworkList: React.FC = () => {
const [state] = useStore();
return <ul>
{
((state && state.frameworks) || []).map((framework, key) => [
<li key={key}>{ framework }</li>
])
}
</ul>;
}
// NewFramework.tsx
import React, { useState } from 'react';
import { useStore } from "../store/state";
import { addFramework } from '../store/actions';
export const NewFramework: React.FC = () => {
const [, store] = useStore();
const [framework, setFramework] = useState("");
const addNewFramework = () => {
store.dispatch(addFramework, framework);
setFramework("");
}
return <div>
<label>New framework:</label>
<br />
<input type="text"
placeholder="enter the new framework"
defaultValue={framework}
onBlur={(e) => setFramework(e.target.value)} />
<button onClick={addNewFramework}>Add</button>
</div>;
}
Finally here’s the contents of state.ts
import { Store } from "aurelia-store";
import { useEffect, useState } from "react";
export type State = {
frameworks: string[];
}
export const initialState = {
frameworks: ["Aurelia", "React", "Angular"]
} as State;
export const store = new Store<State>(initialState, {});
export const useStore = (): [State, Store<State>] => {
const [state, setState] = useState(initialState);
useEffect(() => {
const subscription = store.state.subscribe((state) =>setState(state));
return () => subscription.unsubscribe();
});
return [
state,
store
];
}
It’s essentially creating a new custom hook called useStore, which will create a subscription (plus handling unsubscribes). In the subscription it will set the consuming components state with the newly streamed state. Whenever a new state comes along it updates the components internal state, thus triggers a re-render.