How can we bind to useDispatch?

Hi,

  • useDispatch is of the following type
//JS
const dispatch = useDispatch()
dispatch(() => ({"type": "Increment"}))
  • When I write the bindings as
@module("react-redux")
external useDispatch: (unit)=>((unit => 'a) => unit) = "useDispatch"

rescript formats it to

@module("react-redux")
external useDispatch: (unit, unit => 'a) => unit = "useDispatch"
  • But then the following code does not compile to the required JS playground-link.
@module("react-redux")
external useDispatch: (unit, unit => 'a) => unit = "useDispatch"

let dispatch = useDispatch()
dispatch(() => {"type": "Increment"})

Are you sure this is the correct way of using useDispatch?
I think the actual usage is

const dispatch = useDispatch()

dispatch({ type: "add_user", username: "test"})

Therefore a minimal example would look like this:

type action = AddUser | RemoveUser

type dispatch = (.action) => unit
@module("react-redux")
external useDispatch: unit => dispatch = "useDispatch"

@react.component
let make = () => {
  let dispatch = useDispatch()

  dispatch(. AddUser)
}

Note that the action might need to follow the {type:..., ...} convention. If you are integrating into an existing Redux codebase, you’d need to bind to the action-creators instead and use an abstract type for type action.

1 Like

According to the redux-toolkit documentation

onClick={() => dispatch(increment())}

We get the increment function from slice.actions

Exactly. In your initial example you expressed dispatch as a function that receives a callback of unit => action instead of just an action though:

// dispatch: (unit => action) => unit
dispatch(() => ({"type": "Increment"}))

What is slice?

Usually you would import the action creators from some JS module like this:

module Action = {
  type t
  @module("src/my/actions.js")
  external addUser: string => t = "addUser"

  @module("src/my/actions.js")
  external removeUser: string => t = "addUser"
}

type dispatch = (. Action.t) => unit

@module("react-redux")
external useDispatch: unit => dispatch = "useDispatch"

@react.component
let make = () => {
  let dispatch = useDispatch()

  dispatch(. Action.addUser("patrick"))
}

which compiles to:

var ReactRedux = require("react-redux");
var ActionsJs = require("src/my/actions.js");

var Action = {};

function Playground(Props) {
  var dispatch = ReactRedux.useDispatch();
  return dispatch(ActionsJs.addUser("patrick"));
}

var make = Playground;

exports.Action = Action;
exports.make = make;

Playground Link

Yeah. Thanks you were right. dispatch could accept just the action.

type action

@module("react-redux")
external useDispatch: (unit, . action) => unit = "useDispatch"

@module("userSlice")
external deleteUser: unit => action = "deleteUser"

let dispatch = useDispatch()
dispatch(. deleteUser())

The above code produces the required output.

But this produces the required JS only when dot . is added before the action parameter. Why is that ? or where can I read about the dot before a parameter?

So instead of we manually writing the action creators Redux-toolkit provides a way where we give the reducer(in an object form) and initial state to createSlice and it would return the action creators and the reducer.

The (.) is used to define an uncurried function, otherwise it will invoke extra code that will curry your function before applying (that’s a limitation of the interop system).

To get a better understanding, there’s a summary in our syntax lookup widget with references to the exact documentation here:

Ah right… I guess it’s just a matter of binding to the createSlice function accordingly then?

1 Like