Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

⚛️ 📡 Call your React components

License

NotificationsYou must be signed in to change notification settings

desko27/react-call

Repository files navigation

✓ Lightweight ✓ No deps ✓ SSR ✓ React Native

Call your React components

As simple aswindow.confirm() but it's React:

window.confirmreact-call
constmessage='Sure?'constyes=window.confirm(message)if(yes)thanosSnap()// 🫰
constprops={message:'Sure?'}constyes=awaitConfirm.call(props)if(yes)thanosSnap()// 🫰

Simple yet flexible

Present any piece of UI to the user, wait for the response data:

  • 💬 Confirmations, dialogs, form modals
  • 🔔 Notifications, toasts, popups
  • 📋 Context menus
  • 🎉 Or anything!

Quick setup

npm install react-call

We'll setup a confirmation dialog, but you can setup any component to be callable.

1. ⚛️ Declaration

import{createCallable}from'react-call'interfaceProps{message:string}typeResponse=booleanexportconstConfirm=createCallable<Props,Response>(({ call, message})=>(<divrole="dialog"><p>{message}</p><buttononClick={()=>call.end(true)}>Yes</button><buttononClick={()=>call.end(false)}>No</button></div>))

Along with your props, there is a specialcall prop containing theend() method, which you can use to finish the call and return a response. State, hooks and any other React features are totally fine too.

2. 📡 Rooting

<Root> is what listens to every single call and renders it. Place it anywhere that is visible when making your calls, for instance inApp.tsx:

+ <Confirm.Root />//  ^-- it will render active calls

3. 🎉 Enjoy

You're all done! Now you can do this anywhere in your codebase:

//        ↙ response             props ↘constaccepted=awaitConfirm.call({message:'Continue?'})

Check outthe demo site to see some live examples of other React components being called.

Lazy loading

Use React.lazy to code-split callable components and load them on demand.

import{createCallable}from'react-call'import{lazy,Suspense}from'react'// 1) Lazy-load your componentconstConfirm=createCallable(lazy(()=>import('./Confirm')),// default export required)// 2) Place Root inside a Suspense boundaryexportfunctionApp(){return(<>{/* Other app UI */}<Suspensefallback={null}><Confirm.Root/></Suspense></>)}// 3) Call it as usual (component is fetched on first call)constaccepted=awaitConfirm.call({message:'Continue?'})

Notes:

  • Make sure the lazily imported file has a default export (React.lazy requirement).
  • Wrap<Confirm.Root /> (or an ancestor) in<Suspense> to handle the loading state.
  • The lazy component is split into a separate chunk and downloaded only when first called.

Advanced usage

End from caller

The returned promise can be used to end the call from the caller scope:

constpromise=Confirm.call({message:'Continue?'})// For example, on some event subscriptiononImportantEvent(()=>{Confirm.end(promise,false)})// And still await the response where neededconstaccepted=awaitpromise

While the promise argument is used to target that specific call, all ongoing calls can be affected by omitting it:

// All confirm calls are ended with `false`Confirm.end(false)

Update

The returned promise can also be used to update the call props on the fly:

constpromise=Alert.call({message:'Starting operation...'})awaitasyncOperation()Alert.update(promise,{message:'Completed!'})

While the promise argument is used to target that specific call, all ongoing calls can be affected by omitting it:

// All alert calls are updated with the new message propAlert.update({message:'Completed!'})

Upsert

If you need to ensure only one instance of a component is active at a time, useupsert() instead ofcall(). This is particularly useful for notifications, loading states, or any singleton-like UI:

// First call creates a new instanceconstpromise1=Toast.upsert({message:'Loading...'})// Second call updates the existing instance instead of creating a new oneconstpromise2=Toast.upsert({message:'Almost done...'})// promise1 === promise2 (same instance)console.log(promise1===promise2)// true

Theupsert() method behaves as follows:

  • Creates a new instance if no upsert instance is currently active
  • Updates the existing upsert instance if one is already active
  • Does not affect normalcall() instances
  • Creates a new instance if the previous upsert instance was ended
// Example: Progress notification that updates itselfconstshowProgress=async()=>{Toast.upsert({message:'Starting download...'})for(leti=0;i<=100;i+=10){awaitnewPromise(resolve=>setTimeout(resolve,100))Toast.upsert({message:`Progress:${i}%`})}// End the notificationToast.end(true)}

Exit animations

To animate the exit of your component whencall.end() is run, just pass the duration of your animation in milliseconds to createCallable as a second argument:

+ const UNMOUNTING_DELAY = 500export const Confirm = createCallable<Props, Response>(  ({ call }) => (    <div+     className={call.ended ? 'exit-animation' : '' }    />  ),+ UNMOUNTING_DELAY)

Thecall.ended boolean may be used to apply your animation CSS class.

Passing Root props

You can also read props from Root, which are separate from the call props. To do that, just add your RootProps type to createCallable and pass them to your Root.

Root props will be available to your component viacall.root object.

+ type RootProps = { userName: string }export const Confirm = createCallable<  Props,  Response,+ RootProps>(({ call, message }) => (  ...+   Hi {call.root.userName}!  ...))
<Confirm.Root+ userName='John Doe'/>

You may want to use Root props if you need to:

  • Share the same piece of data to every call
  • Use something that is availble in Root's parent
  • Update your active call components on data changes

FAQ

What if more than one call is active?

<Root> works as a call stack. Multiple calls will render one after another (newer below, which is one on top of the other if your CSS is position fixed/absolute).

Can I place more than one Root?

No. There can only be one<Root> mounted per createCallable(). Avoid placing it in multiple locations of the React Tree loaded at once, an error will be thrown if so.

TypeScript types

You won't need them most likely, but if you want to split the component declaration and such, you may use the types under theReactCall namespace:

importtype{ReactCall}from'react-call'
TypeDescription
ReactCall.Function<Props?, Response?>The call() method
ReactCall.UpsertFunction<Props?, Response?>The upsert() method
ReactCall.Context<Props?, Response?, RootProps?>The call prop in UserComponent
ReactCall.Props<Props?, Response?, RootProps?>Your props + the call prop
ReactCall.UserComponent<Props?, Response?, RootProps?>What is passed to createCallable
ReactCall.Callable<Props?, Response?, RootProps?>What createCallable returns

Errors

ErrorSolution
No <Root> found!You forgot to place the Root, checkRooting section. If it's already in place but not present by the time you call(), you may want to place it higher in your React tree. If you're getting this error on the server seeSSR section.
Multiple instances of <Root> found!You placed more than one Root, checkRooting section as there is a warning about this.

SSR

✅ The react-call setup supportsServer Side Rendering. This means both createCallable and Root component are fine if run or rendered on the server.

However, bear in mind that because the call() method is meant to be triggered by user interaction, it is designed as a client-only feature.

Caution

If call() is run on the server a "No <Root> found!" error will be thrown. As long as you don't run the call() method on the server you'll be fine.

Next.js / RSC

If the original setup is not working for you, export the Root and the rest separately:

+ 'use client'- export const Confirm = createCallable(...)+ export const { Root, ...Confirm } = createCallable(...)

About

⚛️ 📡 Call your React components

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors6


[8]ページ先頭

©2009-2025 Movatter.jp