useProducer
useProducer
is a Reflex Hook that lets you use the producer you passed to <ReflexProvider>
from your component.
const producer = useProducer<Producer>();
Reference
useProducer<T>()
Call useProducer
from a function component to access the producer for the app.
import { useProducer } from "@rbxts/roact-reflex";
import { RootProducer } from "./producer";
function Button() {
const producer = useProducer<RootProducer>();
// ...
}
Parameters
useProducer
takes no parameters.
Returns
useProducer
returns the Reflex producer passed to the <ReflexProvider>
component. If there is more than one provider, the value is the producer from the closest provider above the component in the tree.
This is intended for dispatching actions. If you want to subscribe to state, prefer
useSelector
instead.Your app should only have one root producer. Roact Reflex expects only one producer to be used in your components. Learn more about using a root producer.
Usage
Dispatching actions
Call useProducer
from a component to reference your app's producer.
import { useProducer } from "@rbxts/roact-reflex";
import { RootProducer } from "./producer";
function Button() {
const producer = useProducer<RootProducer>();
// ...
}
useProducer
returns the producer you passed to the <ReflexProvider>
component. It doesn't matter how many components are between your component and the provider because of Roact's context.
You will mainly use this to dispatch actions to your producer. As a shorthand, you can destructure the producer into its actions:
function Button() {
const { increment } = useProducer<RootProducer>();
return <textbutton Event={{ Activated: () => increment(1) }} />;
}
To pass a producer to your components, see <ReflexProvider>
.
Typed useProducer
hook
On its own, useProducer
doesn't know what type of producer you're using. It receives a generic type parameter that lets you specify the type of the producer, but that can be repetitive.
To reduce the amount of typing you have to do, we recommend using the UseProducerHook
type:
import { UseProducerHook, useProducer } from "@rbxts/roact-reflex";
const useAppProducer: UseProducerHook<RootProducer> = useProducer;
Subscribing to state
To access the state from a Roact function component, see useSelector
.
Troubleshooting
I'm getting an error: "useProducer
must be called from within a ReflexProvider
"
This error means that you're trying to use useProducer
in a function component that isn't wrapped in a <ReflexProvider>
:
function App() {
const producer = useProducer<RootProducer>();
// ...
}
// 🔴 You need to wrap your root elements in a <ReflexProvider>
Roact.mount(<App />, container);
Roact Reflex uses Roact contexts to pass the producer to your components and allow them to use Reflex Hooks. If you don't wrap your root elements in a <ReflexProvider>
, your components won't be able to access the producer.
If your app or components use Reflex, you should wrap your root elements in a <ReflexProvider>
:
function App() {
const producer = useProducer<RootProducer>();
// ...
}
// ✅ You can use the root producer in your components
Roact.mount(
<ReflexProvider producer={producer}>
<App />
</ReflexProvider>,
container,
);
My component won't stop dispatching actions
If your component is dispatching actions in a loop, it's likely that your action is running within the body of the component, or it indirectly triggers itself. This can become an issue if components that depend on the state are re-rendered every time the action is dispatched:
function Button() {
const { increment } = useProducer<RootProducer>();
const counter = useSelector((state) => state.counter);
// 🔴 This action updates counter and causes a re-render loop
increment(1);
}
To fix this, you can use useEffect
to dispatch the action when a specific dependency changes:
function Button() {
const { increment } = useProducer<RootProducer>();
const counter = useSelector((state) => state.counter);
// ✅ This action is dispatched once when the component mounts
useEffect(() => {
increment(1);
}, []);
}