swr#useSWRConfig TypeScript Examples

The following examples show how to use swr#useSWRConfig. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: query-data.tsx    From plasmic with MIT License 6 votes vote down vote up
/**
 * Fetches data asynchronously using SWR Hook (https://swr.vercel.app/)
 *
 * @param key a unique key for this data fetch; if data already exists under this
 *   key, that data is returned immediately.
 * @param fetcher an async function that resolves to the fetched data.
 * @param options (optional) an object of options for this hook (https://swr.vercel.app/docs/options).
 * @returns an object with either a "data" key with the fetched data if the fetch
 *   was successful, or an "error" key with the thrown Error if the fetch failed.
 */
export function useMutablePlasmicQueryData<T, E>(
  key: Key,
  fetcher: Fetcher<T>,
  options?: SWRConfiguration<T, E>
) {
  const prepassCtx = React.useContext(PrepassContext);

  const opts: SWRConfiguration = prepassCtx ? { suspense: true } : {};

  const config = useSWRConfig();
  React.useEffect(() => {
    __SWRConfig = config;
  }, [config]);

  return useSWR(key, fetcher, { ...options, ...opts });
}
Example #2
Source File: GuestbookEntry.tsx    From thvu-blog with MIT License 5 votes vote down vote up
export default function GuestbookEntry({ entry, currentUserId }: GuestbookEntryProps) {
  const { user, body, updated_at } = entry;
  const [isDeleting, setIsDeleting] = useState(false);
  const { mutate } = useSWRConfig();

  return (
    <>
      {isDeleting ? (
        <LoadingSpinner />
      ) : (
        <div className="flex flex-col space-y-2">
          <div className="text-gray-700 max-w-none dark:text-gray-300">{body}</div>
          <div className="flex items-center space-x-3">
            {user.image ? (
              <Image
                src={user.image}
                alt={user.name}
                width={20}
                height={20}
                className="rounded-full"
              />
            ) : (
              <DefaultAvatar className="w-5 h-5 rounded-full fill-current text-primary-600 dark:text-primary-400" />
            )}

            <p className="text-sm text-gray-500">{entry.user.name}</p>
            <span className=" text-gray-300 dark:text-gray-700">/</span>
            <p className="text-sm text-gray-300 dark:text-gray-700">
              {format(new Date(updated_at), "d MMM yyyy 'at' h:mm bb")}
            </p>
            {currentUserId === user.id && (
              <>
                <span className="text-gray-300 dark:text-gray-700">/</span>
                <button
                  className="text-sm text-danger-600 dark:text-danger-400"
                  onClick={async (e) => {
                    e.preventDefault();
                    setIsDeleting(true);

                    await fetch(`/api/guestbook/${entry.id}`, {
                      method: "DELETE",
                    });

                    mutate("/api/guestbook");
                  }}
                >
                  Delete
                </button>
              </>
            )}
          </div>
        </div>
      )}
    </>
  );
}
Example #3
Source File: Login.tsx    From nodestatus with MIT License 5 votes vote down vote up
Login: FC = () => {
  const navigate = useNavigate();
  const { mutate } = useSWRConfig();

  const onFinish = useCallback(async (values: { username: string, password: string }) => {
    const { username, password } = values;
    const res = await axios.post<IResp<string>>('/api/session', { username, password });
    const { data } = res;
    if (!data.code) {
      notify('Success', undefined, 'success');
      localStorage.setItem('token', data.data);
      mutate('/api/session', { code: 0, msg: 'OK', data: null }, false).then(() => navigate('/dashboard'));
    }
  }, [navigate, mutate]);

  return (
    <div
      className="flex items-center min-h-screen p-6 bg-violet-50"
      style={{ backgroundImage: `url(${loginBackground})` }}
    >
      <div className="flex-1 h-full max-w-xl md:max-w-4xl mx-auto overflow-hidden bg-white rounded-lg shadow-xl">
        <div className="flex flex-col md:flex-row">
          <div className="h-60 md:h-auto md:w-1/2">
            <img
              aria-hidden="true"
              className="object-cover w-full h-full"
              src={cherry}
              alt="Office"
            />
          </div>
          <div className="flex flex-col items-center justify-center p-6 sm:p-16 md:w-1/2">
            <h1 className="text-2xl font-semibold text-gray-700 mb-6">NodeStatus</h1>
            <Form
              className="w-full"
              initialValues={{ remember: true }}
              onFinish={onFinish}
            >
              <Form.Item
                name="username"
                rules={[{ required: true, message: 'Please input your Username!' }]}
              >
                <Input size="large" prefix={<UserOutlined />} placeholder="Username" />
              </Form.Item>
              <Form.Item
                name="password"
                rules={[{ required: true, message: 'Please input your Password!' }]}
              >
                <Input
                  size="large"
                  prefix={<LockOutlined />}
                  type="password"
                  placeholder="Password"
                />
              </Form.Item>

              <Form.Item>
                <Button type="primary" size="large" htmlType="submit" block>
                  Log in
                </Button>
              </Form.Item>
            </Form>
          </div>
        </div>
      </div>
    </div>
  );
}
Example #4
Source File: query-data.tsx    From plasmic with MIT License 5 votes vote down vote up
/**
 * Fetches data asynchronously. This data should be considered immutable for the
 * session -- there is no way to invalidate or re-fetch this data.
 *
 * @param key a unique key for this data fetch; if data already exists under this
 *   key, that data is returned immediately.
 * @param fetcher an async function that resolves to the fetched data.
 * @returns an object with either a "data" key with the fetched data if the fetch
 *   was successful, or an "error" key with the thrown Error if the fetch failed.
 */
export function usePlasmicQueryData<T>(
  key: Key,
  fetcher: Fetcher<T>
): { data?: T; error?: Error; isLoading?: boolean } {
  const prepassCtx = React.useContext(PrepassContext);

  // @plasmicapp/query is optimized for SSR, so we do not revalidate
  // automatically upon hydration; as if the data is immutable.
  const opts: SWRConfiguration = {
    revalidateIfStale: false,
    revalidateOnFocus: false,
    revalidateOnReconnect: false,
  };
  if (prepassCtx) {
    // If we're doing prepass, then we are always in suspense mode, because
    // react-ssr-prepass only works with suspense-throwing data fetching.
    opts.suspense = true;
  }

  const config = useSWRConfig();
  React.useEffect(() => {
    __SWRConfig = config;
  }, [config]);

  const resp = useSWR(key, fetcher, opts);
  if (resp.data) {
    return { data: resp.data };
  } else if (resp.error) {
    return { error: resp.error };
  } else {
    return { isLoading: true };
  }
}
Example #5
Source File: index.tsx    From thvu-blog with MIT License 4 votes vote down vote up
export default function Guestbook({ fallbackData }: { fallbackData: GuestBookEntry[] }) {
  const [form, setForm] = useState<FormState>(FormState.INITIAL);
  const inputEl = useRef<HTMLTextAreaElement>(null);
  const { data: session } = useSession();
  const { error: entriesError, data: entries } = useSWR<GuestBookEntry[]>(
    "/api/guestbook",
    fetcher,
    {
      fallbackData,
    }
  );
  const { mutate } = useSWRConfig();

  return (
    <>
      <LoginView message="Login to sign the guestbook." />
      {Boolean(session?.user) && (
        <div className="border-2 border-gray-400 dark:border-gray-600 rounded-md p-6 prose dark:prose-dark lg:prose-xl">
          <p>Leave a message!</p>
          <form
            className="w-full my-4"
            onSubmit={async (e) => {
              e.preventDefault();
              setForm(FormState.LOADING);

              const res = await fetch("/api/guestbook", {
                body: JSON.stringify({
                  body: inputEl.current?.value,
                }),
                headers: {
                  "Content-Type": "application/json",
                },
                method: "POST",
              });

              const { error } = await res.json();
              if (error) {
                setForm(FormState.ERROR);
                return;
              }

              if (inputEl.current) inputEl.current.value = "";
              mutate("/api/guestbook");
              setForm(FormState.SUCCESS);
              fireConfetti();
            }}
          >
            <textarea
              ref={inputEl}
              aria-label="Your message"
              placeholder="Your message..."
              required
              style={{ resize: "none" }}
              className="px-4 py-2 my-4 focus:ring-primary-500 focus:border-primary-500 block w-full border-gray-300 rounded-md bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100"
            />
            <Button type="submit">
              {form === FormState.LOADING ? <LoadingSpinner /> : "Sign"}
            </Button>
          </form>
          {form === FormState.ERROR && <ErrorMessage>An error occurred.</ErrorMessage>}
          {form === FormState.SUCCESS && (
            <SuccessMessage>Awesome! Thank you for signing my guestbook.</SuccessMessage>
          )}
        </div>
      )}
      <div className="mt-4 space-y-8">
        {entriesError && (
          <ErrorMessage>
            An unexpected error occurred. The entries are not available for now. Please try again
            later
          </ErrorMessage>
        )}
        {entries ? (
          entries.map((entry) => (
            <GuestbookEntry key={entry.id} entry={entry} currentUserId={session?.id as string} />
          ))
        ) : (
          <LoadingSpinner />
        )}
      </div>
    </>
  );
}
Example #6
Source File: Badge.tsx    From thvu-blog with MIT License 4 votes vote down vote up
export default function Badge({ skill, user, currentUserId }: Props) {
  const [state, setState] = useState<FormState>(FormState.INITIAL);
  const { mutate } = useSWRConfig();
  async function onEndorse(skillId: string) {
    setState(FormState.LOADING);
    const res = await fetch("/api/endorsement", {
      body: JSON.stringify({
        skillId,
      }),
      headers: {
        "Content-Type": "application/json",
      },
      method: "POST",
    });
    const { error } = await res.json();
    if (error) {
      setState(FormState.ERROR);
      return;
    }
    mutate("/api/skill-category");
    setState(FormState.SUCCESS);
    fireConfetti();
  }
  const isUserEndorsed = skill?.users?.find((u) => u.id === currentUserId);

  return (
    <div className="space-y-4">
      <div className="flex items-center text-base font-semibold">
        {state === FormState.LOADING ? (
          <div className="flex items-center justify-center w-8 h-8">
            <LoadingSpinner />
          </div>
        ) : isUserEndorsed ? (
          <button
            className="font-semibold disabled:hover:cursor-not-allowed text-success-700 dark:text-success-400"
            title="You already endorsed this skill!"
            disabled
          >
            <DoneIcon className="inline w-8 h-8 fill-current " />
          </button>
        ) : (
          <button
            className="font-semibold disabled:hover:cursor-not-allowed text-primary-600 dark:text-primary-400 hover:text-gray-700 dark:hover:text-gray-300 disabled:text-gray-700 dark:disabled:text-gray-300 "
            disabled={!Boolean(user)}
            title={!Boolean(user) ? "Please login first." : "Endorse this skill!"}
            onClick={() => onEndorse(skill.id)}
          >
            <ButtonIcon className="inline w-8 h-8 fill-current " />
          </button>
        )}
        <span className="ml-2">{skill.name}</span>
      </div>
      <div className="flex items-center gap-1 flex-wrap">
        {skill.users.map((user) => (
          <span title={user.name} key={user.id} className="w-8 h-8">
            {user.image ? (
              <Image
                src={user.image}
                alt={user.name}
                width={32}
                height={32}
                className="rounded-full"
              />
            ) : (
              <DefaultAvatar className="w-8 h-8 p-0.5 rounded-full fill-current text-primary-600 dark:text-primary-400 border-2 border-solid border-primary-600 dark:border-primary-400" />
            )}
          </span>
        ))}
      </div>
      {skill.users.length > 0 && (
        <p className="text-sm text-gray-600 dark:text-gray-400">
          <strong className="text-black dark:text-white">{skill.users.length}</strong>{" "}
          {`${skill.name} endorsement${skill.users.length > 1 ? "s" : ""} from:`}
          <span className="mx-2">{skill.users.map((u) => u.name).join(", ")}</span>
        </p>
      )}
      {state === FormState.ERROR && <ErrorMessage>An unexpected error occurred.</ErrorMessage>}
      {state === FormState.SUCCESS && (
        <SuccessMessage>Thank you for your endorsement!</SuccessMessage>
      )}
    </div>
  );
}
Example #7
Source File: useEtherSWR.ts    From ether-swr with MIT License 4 votes vote down vote up
function useEtherSWR<Data = any, Error = any>(
  ...args: any[]
): SWRResponse<Data, Error> {
  let _key: ethKeyInterface
  let fn: any //fetcherFn<Data> | undefined
  let config: EthSWRConfigInterface<Data, Error> = { subscribe: [] }
  let isMulticall = false
  if (args.length >= 1) {
    _key = args[0]
    isMulticall = Array.isArray(_key[0])
  }
  if (args.length > 2) {
    fn = args[1]
    //FIXME we lost default value subscriber = []
    config = args[2]
  } else {
    if (typeof args[1] === 'function') {
      fn = args[1]
    } else if (typeof args[1] === 'object') {
      config = args[1]
    }
  }

  config = Object.assign({}, useContext(EthSWRConfigContext), config)

  if (fn === undefined) {
    fn = config.fetcher || etherJsFetcher(config.web3Provider, config.ABIs)
  }

  // TODO LS implement a getTarget and change subscribe interface {subscribe: {name: "Transfer", target: 0x01}}
  const [target] = isMulticall
    ? [_key[0][0]] // pick the first element of the list.
    : _key

  const { cache } = useSWRConfig()
  // we need to serialize the key as string otherwise
  // a new array is created everytime the component is rendered
  // we follow SWR format
  const normalizeKey = isMulticall ? JSON.stringify(_key) : _key

  // base methods (e.g. getBalance, getBlockNumber, etc)
  useEffect(() => {
    if (!config.web3Provider || !config.subscribe || Array.isArray(target)) {
      // console.log('skip')
      return () => ({})
    }
    // console.log('effect!')
    const contract = buildContract(target, config)

    const subscribers = Array.isArray(config.subscribe)
      ? config.subscribe
      : [config.subscribe]

    const instance: Contract | Provider = contract || config.web3Provider

    subscribers.forEach(subscribe => {
      let filter
      const internalKey = unstable_serialize(normalizeKey)
      if (typeof subscribe === 'string') {
        filter = subscribe
        instance.on(filter, () => {
          // console.log('on(string):', { filter }, Array.from(cache.keys()))
          mutate(internalKey, undefined, true)
        })
      } else if (typeof subscribe === 'object' && !Array.isArray(subscribe)) {
        const { name, topics, on } = subscribe
        const args = topics || []
        filter = contract ? contract.filters[name](...args) : name
        // console.log('subscribe:', filter)
        instance.on(filter, (...args) => {
          if (on) {
            // console.log('on(object):', { filter }, Array.from(cache.keys()))
            on(cache.get(internalKey), ...args)
          } else {
            // auto refresh
            // console.log('auto(refresh):', { filter }, Array.from(cache.keys()))
            mutate(internalKey, undefined, true)
          }
        })
      }
    })

    return () => {
      subscribers.forEach(filter => {
        instance.removeAllListeners(filter)
      })
    }
  }, [unstable_serialize(normalizeKey), target])

  return useSWR(normalizeKey, fn, config)
}