Passing arguments on Dfinity app with React frontend using useUpdateCall

Title: Issue with useUpdateCall in React Note App (Dynamic Arguments Issue)

Body:

Hi Community,

I’m developing a Note App backed by a Dfinity canister, using React and the @ic-reactor/react library. I’m encountering an issue with dynamically passing arguments to the useUpdateCall hook for calling the createNote backend function.

What I’m Trying to Achieve

I want to allow users to create a new note by dynamically passing a title (string) from the frontend to the backend. Previously, I had two inputs (title and content) that mapped to the backend createNote function, but to simplify debugging, I’ve reduced it to just one input (title).

The backend createNote function is defined as follows:

public shared func createNote(titleText: Text): async () {

Debug.print("Creating new note with title: " # titleText);

// Additional logic for creating a note…

};

On the frontend, I’m using the useUpdateCall hook to make this call:

const { call, data, loading } = useUpdateCall({

functionName: “createNote”,

onLoading: (loading) => console.log(“Loading:”, loading),

onError: (error) => console.error(“Error:”, error),

onSuccess: (result) => {

console.log(“Note created successfully:”, result);

},

});

const handleSubmit = (event: FormEvent) => {

event.preventDefault();

console.log(“Calling backend with:”, note.title);

// Dynamically pass arguments to call

call({ args: [note.title] });

};

The Problem

When I dynamically pass the arguments to call as shown above, I receive the following error:

Error: Wrong number of message arguments

However, if I replace the args with static text like this:

call({ args: [“Static Title”] });

The backend call works as expected, and the note is successfully created.

What I’ve Tried

  1. Testing Backend Directly:

Using dfx canister call works as expected:

dfx canister call NoteApp createNote ‘( “Test Title” )’

Output:

Creating new note with title: Test Title

  1. Static Arguments Work:

Hardcoding args in the call function (call({ args: [“Static Title”] })) works perfectly.

  1. Dynamic Arguments Fail:

When passing user input dynamically (call({ args: [note.title] })), the call fails with the “Wrong number of message arguments” error.

  1. Reduced to One Input:

Originally, the createNote function accepted two arguments (title and content), but to simplify debugging, I’ve reduced it to accept only one (titleText).

  1. Checked Argument Types:

• note.title is a string, which should map correctly to the Text type expected by the backend.

Expected Outcome

I expect call({ args: [note.title] }) to pass the dynamic argument correctly to the backend and create a new note.

My Question

Why does useUpdateCall fail when passing dynamic arguments to call, even though static arguments work fine? Is there something I need to do differently when passing arguments dynamically?

Any help or guidance would be greatly appreciated!

Thank you for your time and support!

This updated post clarifies the context of reducing from two inputs to one and highlights the debugging effort. Let me know if this works for you or if you’d like to add anything further!

CC @b3hr4d since this is about ic-reactor

1 Like

Hello,

This means the hook is working just fine!

No, its just work exactly like other react hooks!

Debug Suggestion:

The call function just accepts arguments as array, do not need to pass object and args.

Call it like this

call([note.title])

To be more clear this is the options you have

const Example: React.FC = () => {
  const [note, setNote] = useState<Note>({ title: '' });

  const { call, data, loading } = useUpdateCall({
    functionName: "createNote",
    args: [note.title], // You can pass args here directly
    // ...
  });

  const handleSubmit = (event: FormEvent) => {
    event.preventDefault();
    console.log("Calling backend with:", note.title);
    // You can either call without args (will use the ones from hook config)
    call();
    // Or override them during the call
    call([note.title]);
  };

  // ...existing code...
};

Solved! Thank you!

import React, { useState, FormEvent } from 'react';
import { useQueryCall, useUpdateCall } from '@ic-reactor/react';
import { Note } from '../.types';

type CreateAreaProps = {
    refetchNotes: () => void; // Callback to refresh notes in App.tsx
  };

const CreateArea: React.FC<CreateAreaProps> = ({ refetchNotes }) => {
  const [isExpanded, setExpanded] = useState(false);
  const [error, setError] = useState<string | null>(null); // Error can be string or null
  const [note, setNote] = useState({ title: '', content: '' });

  const { call , data, loading } = useUpdateCall({
    functionName: "createNote", // Backend function name
    // args: ['noteTitle2', 'noteContent2'],
    args: [note.title],
    onLoading: (loading) => console.log("Loading:", loading),
    onError: (error) => {
      console.error("Error creating note:", error);
      setError(error?.message || "An unknown error occurred.");
    },
    onSuccess: (result) => {
      console.log("Note created successfully:", result);
      setNote({ title: "", content: "" }); // Clear the form
      setError(null); // Clear errors
    },
  });

  const handleSubmit = (event: FormEvent) => {
    event.preventDefault();
    // if (!note.title.trim() || !note.content.trim()) {
    //   setError("Title and content are required.");
    //   console.error("Title and content are required.");
    //   return;
    // }
    console.log("Calling backend with:", note.title, note.content);
    // Pass arguments dynamically to `call`
    call();
  };
1 Like

You’re welcome.
Please feel free to open any issues or suggestions about the IC-reactor on GitHub.