An implementation of React hooks for Roact. Does not make any modifications to Roact itself.
local Hooks = require(ReplicatedStorage.Hooks)
local Roact = require(ReplicatedStorage.Roact)
-- `props` are our normal passed in properties.
-- `hooks` is passed in by roact-hooks itself.
local function Example(props, hooks)
local count, setCount = hooks.useState(0)
hooks.useEffect(function()
print("the count is", count)
end)
return Roact.createElement(Button, {
onClick = function()
setCount(count + 1)
end,
text = count,
})
end
-- This returns a component that you can call `Roact.createElement` with
Example = Hooks.new(Roact)(Example)
Hooks.new(Roact: Roact) -> (render: (props, hooks) -> RoactComponent | nil, options?: {
name?: string,
defaultProps?: Map<any, any>,
componentType?: string,
validateProps?: (props) -> (false, message: string) | true,
}) -> RoactComponent)
It is required you pass in the Roact you are using, since you can't combine multiple versions of Roact together.
Returns a function that can be used to create a new Roact component with hooks. An optional dictionary can be passed in. The following are the valid keys that can be used, and what they do.
Refers to the name used in debugging. If it is not passed, it'll use the function name of what was passed in. For instance, Hooks.new(Roact)(Component)
will have the component name "Component"
.
Defines default values for props to ensure props will have values even if they were not specified by the parent component.
useState<T>(defaultValue: T | (() -> T)) -> (T, update: (value: T | ((prevState: T) -> T)) -> ())
Used to store a stateful value. Returns the current value, and a function that can be used to set the value.
useEffect(callback: () -> (() -> void)?, dependencies?: any[])
Used to perform a side-effect with a callback function.
This callback function can return a destructor. When the component unmounts or the dependencies change, this function will be called.
You can also pass in a list of dependencies to useEffect
. If passed, then only when those dependencies change will the callback function be re-ran.
useContext(context: RoactContext<T>) -> T
Returns the value of the context.
useValue(value: T) -> { value: T }
Similar to useRef in React. Creates a table that you can mutate without re-rendering the component every time. Think of it like a class variable (self.something = 1
vs. self:setState({ something = 1 })
).
useCallback<F: (...args: any[]) -> any>(callback: F, dependencies: any[]): F
Returns a memoized callback.
useCallback(callback, dependencies)
is equivalent to useMemo(function() return callback end, dependencies)
.
useMemo(createValue: () -> T, dependencies: any[]): T
Returns a memoized value.
useMemo
will only recalculate the inner value when the dependencies have changed.
The function passed to useMemo
runs during rendering, so don't perform any side effects.
If no array is provided, a new value will be computed on every render.
useBinding(defaultValue: T) -> RoactBinding<T>, (newValue: T) -> void
These can then be used just like normal bindings in Roact.
useReducer(reducer: (state: T, action: A), initialState: T) -> (T, (action: A) -> void)
An alternative to useState
that uses a reducer rather than state directly. If you’re familiar with Rodux, you already know how this works.
local initialState = { count = 0 }
local function reducer(state, action)
if action.type == "increment" then
return {
count = state.count + 1,
}
elseif action.type == "decrement" then
return {
count = state.count - 1,
}
else
error("Unknown type: " .. tostring(action.type))
end
end
local function Counter(_props, hooks)
local state, dispatch = hooks.useReducer(reducer, initialState)
return e(Frame, {}, {
Counter = e(Text, {
text = state.count,
}),
Increment = e(Button, {
onClick = function()
dispatch({
type = "increment",
})
end,
}),
Decrement = e(Button, {
onClick = function()
dispatch({
type = "decrement",
})
end,
}),
})
end
Roact is also provided in the hooks argument. This is useful if custom hooks need direct access to Roact.
-- useCustomHook.lua
local function useCustomHook(hooks)
local Roact = hooks.Roact
end
-- Example.lua
local function Example(props, hooks)
local example = useCustomHook(hooks)
return nil
end
The rules of roact-hooks are the same as those found in React.
Call all hooks from the top level of your function. Do not use them in loops or conditions.
You can only call hooks from:
- Roact function components
- Custom hooks (a function that begins with the word
use
)