Giter Club home page Giter Club logo

Comments (9)

tyom avatar tyom commented on June 6, 2024

Hi @nirvdrum. Thanks for your feedback.

I'm having trouble understanding the use case and the specific issue with 3rd party context. Would it be possible to provide an example to help me understand it? A PR would certainly be welcome as it could contain an example SB story that shows it in action.

from storybook-addons.

nirvdrum avatar nirvdrum commented on June 6, 2024

Hi @tyom. Thanks for taking a look. This is my first Storybook project, so apologies in advance if I've got something wrong.

To make the example concrete, I'm using @auth0/auth0-react to handle authentication for my app. This library ships with an Auth0Context and components consume it using a useAuth0 hook. As an example, a call might look like:

const { isAuthenticated, isLoading, loginWithRedirect } = useAuth0();

The definition of useAuth0 is:

const useAuth0 = <TUser extends User = User>(): Auth0ContextInterface<TUser> =>
  useContext(Auth0Context) as Auth0ContextInterface<TUser>;

As you can see, useAuth0 is a simple wrapper around React's useContext, supplying the Auth0 context object. That's the one I need to mock to simulate a logged-in user.

My attempt at using the add-on looked like:

export const Default = Template.bind({});
Default.decorators = [withReactContext({
  context: Auth0Context,
  initialState: {
    isAuthenticated: true,
    isLoading: false,
    getAccessTokenSilently: () => new Promise((resolve) => resolve('My JWT')),
    user: {
      sub: "auth0|some_auth0_id",
      name: "John Doe"
    },
  }
})];

So, I set the initialState value to an object that conforms to the type the context provides. As far as I can tell, storybook-react-context assumes the context value is going to be a tuple of (currentValue, setValue) by way of wrapping the object in a useReducer call. It changes the type of the context value to match that assumption. Consequently, using the add-on to mock out the Auth0Provider creates a situation where the useAuth0 call adds an additional level of indirection. The call would need to be something like:

const { isAuthenticated, isLoading, loginWithRedirect } = useAuth0()[0];

While I could wrap the Auth0Context in a custom component and try to handle the change this add-on is making, I can't change the 3rd party context provider to conform. Unless I've managed to use the add-on wrong, I can't see a way to make this work. Naively, it looks to me like the add-on should not assume a reducer is being used and make the caller supply the two reducer parts if one is to be used.

To solve the problem in the meanwhile, I took the spirit of this add-on and wrote my own decorator, added to preview.tsx:

export const decorators = [
  (Component: React.ComponentType<unknown>) => {
    const initialValue = useAuth0();

    return (
      <Auth0Context.Provider
        value={{
          ...initialValue,
          isAuthenticated: true,
          isLoading: false,
          getAccessTokenSilently: () => new Promise((resolve) => resolve('My JWT')),
          user: {
            sub: 'auth0|some_auth0_id',
            name: 'John Doe'
          }
        }}
      >
        <Component />
      </Auth0Context.Provider>
    );
  }
];

Please let me know if you need any additional information.

from storybook-addons.

tyom avatar tyom commented on June 6, 2024

Hi @nirvdrum. Apologies for the radio silence. I've just done some housekeeping in the library and also looked into the use case you describe here. There is now a new option in the storybook-react-context decorator called useReducer which is a boolean, and when it's set to false it will not use React's useReducer in the context provider and pass the initialState directly to its value. I've added this example to the lib's Storybook examples. I hope it helps to solve the problem you're facing.

Try to upgrade to version 0.5.0 to get this functionality.

Let me know if that helps or if I misinterpreted your use case.

from storybook-addons.

LongLiveCHIEF avatar LongLiveCHIEF commented on June 6, 2024

This only helps with the initial value. However, if context is more than just a single object of primitive values, it doesn't help. For example, many providers export a {value, setValue} as an internal useState.

useReducer: false will allow the value to be set, but it completely removes the rest of the interface from the context, and so setValue is no longer a function, and that means I can't change contexts in my stories

from storybook-addons.

tyom avatar tyom commented on June 6, 2024

Could you help setting up a test case for this, @LongLiveCHIEF?

from storybook-addons.

LongLiveCHIEF avatar LongLiveCHIEF commented on June 6, 2024

Simple example:

const ColorContext = React.createContext()

interface ColorThemeContext {
  background: Color;
  border: Color;
}

const ColorProvider({children}){
  const [context, setContext] = useState<ColorThemeContext>()
  
  return <ColorContext.Provider value={{context, setContext}}>{children}</ColorContext.Provider>
}

The idea would be that inside the story we'd want to use a useContext hook:

export const SomeStory = () => {

  const { context, setContext } = useContext(ColorContext)
 
 //.... some story jsx  
}

The problem is that currently when i decorate with this addon, the context has the correct value from initialState, but setContext has been stripped from the ColorContext context object entirely (along with any other properties)

granted, that may be outside the use case of this addon.

from storybook-addons.

LongLiveCHIEF avatar LongLiveCHIEF commented on June 6, 2024

Maybe we could add a merge or deepMerge option or something like that.

from storybook-addons.

tyom avatar tyom commented on June 6, 2024

The use case for this addon when I initially created was to tap into the component's context in Storybook and change it at will. Now I realise that the use case is not even properly presented in the examples I have. I need to review those use cases and present them better while looking into making sure that the provider value is not assumed to be a tuple from useReducer. For example, a use case for Auth0 context, as outlined in this issue. I'll post an update here when I had a chance to do that. Thanks.

from storybook-addons.

tyom avatar tyom commented on June 6, 2024

I've refactored the storybook-react-context (v0.6.0) package which now has useProviderValue parameter. The value return from the call of this function is set as the value of the context provider. This should give the necessary tools to customise the context in a way that is described in this issue.

Please note that this is a breaking change. The useReducer parameter has been removed and context renamed to Context to make it clearer that this is React's context rather than story context. See the updated example stories for the updated use cases.

Let me know if it solves your issue.

from storybook-addons.

Related Issues (7)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.