import React, { useState } from 'react'; import axios from 'axios'; import { Alert, Box, Button, Group, Heading, Image, Input, Set, Spinner } from 'fannypack'; import { storiesOf } from '@storybook/react'; import { cache, useCache, useGetStates, useLoads, useDeferredLoads } from '../index'; import * as api from './api'; storiesOf('useLoads', module) .add('basic', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('basic', getRandomDog); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('basic (deferred)', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useDeferredLoads('basic', getRandomDog); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with function variables', () => { function Component() { const [breed, setBreed] = React.useState('beagle'); const getRandomDogByBreed = React.useCallback( breed => axios.get(`https://dog.ceo/api/breed/${breed}/images/random`), [] ); const randomDogRecord = useLoads('functionVariables', getRandomDogByBreed, { variables: [breed] }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with function variables (deferred)', () => { function Component() { const getRandomDogByBreed = React.useCallback( breed => axios.get(`https://dog.ceo/api/breed/${breed}/images/random`), [] ); const randomDogRecord = useDeferredLoads('functionVariables', getRandomDogByBreed); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('suspense', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('suspense', getRandomDog, { suspense: true }); return ( {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ( }> ); }) .add('custom delay', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useDeferredLoads(getRandomDog, { delay: 1000 }); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('no delay', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useDeferredLoads(getRandomDog, { delay: 0 }); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with error', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/sssss/random'), []); const randomDogRecord = useDeferredLoads(getRandomDog, { delay: 1000 }); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with timeout', () => { function Component() { const fn = React.useCallback(() => new Promise(res => setTimeout(() => res('this is data'), 2000)), []); const randomDogRecord = useDeferredLoads(fn, { timeout: 1000 }); return ( {randomDogRecord.isIdle && } {(randomDogRecord.isPending || randomDogRecord.isPendingSlow) && } {randomDogRecord.isPendingSlow && 'taking a while'} {randomDogRecord.isResolved && {randomDogRecord.response}} ); } return ; }) .add('with dependant useLoads', () => { function Component({ movieId }) { const getMovie = React.useCallback(async movieId => { const movie = await api.getMovie(movieId); return movie; }, []); const movieRecord = useLoads('movie', getMovie, { variables: [movieId] }); const movie = movieRecord.response; const getReviews = React.useCallback(async movieId => { const reviews = await api.getReviewsByMovieId(movieId); return reviews; }, []); const reviewsRecord = useLoads('reviews', getReviews, { variables: () => [movie.id] }); const reviews = reviewsRecord.response; return ( {movieRecord.isPending && } {movieRecord.isResolved && ( Title: {movie.title} {reviewsRecord.isResolved && reviews.map(review => review.comment)} )} ); } return ; }) .add('with dependant useLoads (deferred)', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('dependant', getRandomDog, { defer: true }); const saveDog = React.useCallback(async imageSrc => new Promise(res => res(`Saved. Image: ${imageSrc}`)), []); const saveDogRecord = useDeferredLoads(saveDog, { variables: () => [randomDogRecord.response.data.message] }); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( {randomDogRecord.response && ( Dog )} {saveDogRecord.isIdle && ( )} {saveDogRecord.isResolved && {saveDogRecord.response}} )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with inputs', () => { function Component() { const [breed, setBreed] = useState('dingo'); const getRandomDogByBreed = React.useCallback( () => axios.get(`https://dog.ceo/api/breed/${breed}/images/random`), [breed] ); const randomDogRecord = useLoads('inputs', getRandomDogByBreed); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with update fn', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const getRandomDoberman = React.useCallback( () => axios.get('https://dog.ceo/api/breed/doberman/images/random'), [] ); const randomDogRecord = useLoads('updateFn', getRandomDog, { update: getRandomDoberman }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} ); } return ; }) .add('with update fns', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const getRandomDoberman = React.useCallback( () => axios.get('https://dog.ceo/api/breed/doberman/images/random'), [] ); const getRandomPoodle = React.useCallback(() => axios.get('https://dog.ceo/api/breed/poodle/images/random'), []); const randomDogRecord = useLoads('updateFns', getRandomDog, { update: [getRandomDoberman, getRandomPoodle] }); const [loadDoberman, loadPoodle] = randomDogRecord.update; return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} ); } return ; }) .add('with optimistic updates', () => { function Component({ movieId }) { const [ratingValue, setRatingValue] = React.useState(); const getMovie = React.useCallback(() => api.getMovie(movieId), [movieId]); const movieRecord = useLoads('movie', getMovie); const movie = movieRecord.response || {}; const updateMovie = React.useCallback( () => meta => { meta.setResponse(movie => ({ ...movie, imdbRating: ratingValue })); return api.updateMovie(movieId, { imdbRating: ratingValue }); }, [movieId, ratingValue] ); const updateMovieRecord = useDeferredLoads('movie', updateMovie); return ( {movieRecord.isPending && } {movieRecord.isResolved && ( {movie.title} Rating: {movie.imdbRating} setRatingValue(e.target.value)} placeholder="Enter new rating" value={ratingValue} /> )} {movieRecord.isRejected && {movieRecord.error.message}} ); } return ; }) .add('with onResolve', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const onResolve = React.useCallback(record => console.log('success', record), []); const randomDogRecord = useLoads('basic', getRandomDog, { onResolve }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with onReject', () => { function Component() { const getSomething = React.useCallback(async () => { return new Promise((res, rej) => setTimeout(() => rej(new Error('This is an error.')), 1000)); }, []); const onReject = React.useCallback(error => console.log('error', error), []); const somethingRecord = useLoads('rejectHook', getSomething, { onReject }); return ( {somethingRecord.isPending && } {somethingRecord.isRejected && {somethingRecord.error.message}} ); } return ; }) .add('with revalidateTime', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('revalidateTime', getRandomDog, { revalidateTime: 5000, loadPolicy: 'cache-first' }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with cacheTime', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('cacheTime', getRandomDog, { cacheTime: 5000 }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with dedupingInterval', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('dedupingInterval', getRandomDog, { dedupingInterval: 2000 }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with debounce', () => { function Component() { const [value, setValue] = React.useState('poodle'); const getRandomDog = React.useCallback( ({ value }) => axios.get(`https://dog.ceo/api/breed/${value}/images/random`), [] ); const randomDogRecord = useLoads('debounce', getRandomDog, { debounce: 1000, variables: [{ value }] }); return ( setValue(e.target.value)} value={value} /> {randomDogRecord.isPending && } {randomDogRecord.isResolved && randomDogRecord.response && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with pollingInterval', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('pollingInterval', getRandomDog, { pollingInterval: 2000 }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with rejectRetryInterval', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/sssss/random'), []); const randomDogRecord = useDeferredLoads(getRandomDog, { rejectRetryInterval: 5000 }); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with rejectRetryInterval (function)', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/sssss/random'), []); const randomDogRecord = useDeferredLoads(getRandomDog, { rejectRetryInterval: count => count * 5000 }); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with load-only loadPolicy', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('loadOnly', getRandomDog, { loadPolicy: 'load-only' }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with cache-and-load loadPolicy', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('cacheAndLoad', getRandomDog, { loadPolicy: 'cache-and-load' }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with cache-first loadPolicy', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('cacheFirst', getRandomDog, { loadPolicy: 'cache-first' }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with key-only cacheStrategy', () => { function Component() { const [breed, setBreed] = React.useState('beagle'); const getRandomDogByBreed = React.useCallback( breed => axios.get(`https://dog.ceo/api/breed/${breed}/images/random`), [] ); const randomDogRecord = useLoads('functionVariables', getRandomDogByBreed, { cacheStrategy: 'key-only', variables: [breed] }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }) .add('with initialResponse', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useLoads('basic', getRandomDog, { initialResponse: { data: { message: 'https://images.dog.ceo/breeds/schnauzer-miniature/n02097047_2002.jpg' } } }); return ( {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } return ; }); storiesOf('useCache', module).add('cache', () => { function Component() { const getRandomDog = React.useCallback(() => axios.get('https://dog.ceo/api/breeds/image/random'), []); const randomDogRecord = useDeferredLoads('basic', getRandomDog); return ( {randomDogRecord.isIdle && } {randomDogRecord.isPending && } {randomDogRecord.isResolved && ( Dog )} {randomDogRecord.isRejected && {randomDogRecord.error.message}} ); } function Cache() { const randomDogRecord = useCache('basic'); if (randomDogRecord && randomDogRecord.response) { return ( Cached: Dog ); } return null; } return ( ); }); storiesOf('useGetStates', module).add('basic', () => { function Component() { const getSomething = React.useCallback(async () => { return new Promise(res => setTimeout(() => res('This is something.'), 1000)); }, []); const somethingRecord = useLoads('something', getSomething); const getAnother = React.useCallback(async () => { return new Promise(res => setTimeout(() => res('This is another.'), 5000)); }, []); const anotherRecord = useLoads('another', getAnother, { timeout: 3000 }); const states = useGetStates(somethingRecord, anotherRecord); return ( {states.isPending && 'Pending...'} {states.isPendingSlow && ' Taking a while...'} {states.isResolved && `Both records have resolved. ${somethingRecord.response} ${anotherRecord.response}`} ); } return ; }); storiesOf('cache', module).add('cache.clear', () => { function Component() { return ( ); } return ; });