Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to load an external scripts #334

Closed
cauealvesbraz opened this issue Jul 26, 2016 · 7 comments
Closed

How to load an external scripts #334

cauealvesbraz opened this issue Jul 26, 2016 · 7 comments

Comments

@cauealvesbraz
Copy link

Hello,

Today I'm try to use the react-storybook for building a component thats use the SDK of Facebook. I will try something like this:

componentWillMount() {
  (function(d, s, id){
     var js, fjs = d.getElementsByTagName(s)[0];
     if (d.getElementById(id)) {return;}
     js = d.createElement(s); js.id = id;
     js.src = "//connect.facebook.net/en_US/sdk.js";
     fjs.parentNode.insertBefore(js, fjs);
  }(document, 'script', 'facebook-jssdk'));
}

And I did not succeed. The script loads up if I see on the network of browser. But it is not accessible through the console or even within React functions.

I believe it can be related to how the encapsulation react-storybook works.

@arunoda
Copy link
Member

arunoda commented Jul 26, 2016

Since we are running inside an inframe, you wouldnt see it directly in the console.
But your other method will see it.

Make sure, we only run a component once. Hooks like componentWillRecieveProps won't work. When you change a story, we will run it from the begining after cleaning the DOM.

@cauealvesbraz
Copy link
Author

@arunoda Nice! Works fine to me :)

@adamellsworth
Copy link

adamellsworth commented Feb 28, 2017

What if you need a cdn resource before the stories run/mount?

var App = (function () {
  return function () {
     loadScript('cdn.file.js' , function scriptsDidLoadCallback () {
       storiesOf('Button Test', module).add('', () => (<Button/>));
     });
  }
})();

App();

which assumes the setup is something like this:

function loadScript (file, callback) {
  source = document.createElement('script');
  source.src = file;
  source.async = true;
  // ...
  source.onload = function () {
    callback (); // aka: scriptsDidLoadCallback
  };
}

@jonnybot0
Copy link

I need something like what @adamellsworth described, but his code didn't seem to work. While I didn't get any errors, my stories weren't actually loaded at runtime.

@3mcd
Copy link

3mcd commented Oct 23, 2018

Leaving this snippet here for anyone who may have a similar need to load scripts per-story:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Script extends Component {
  static propTypes = {
    src: PropTypes.string.isRequired,
  };

  state = {
    loaded: false,
  };

  componentWillMount() {
    const head = document.querySelector('head');
    const script = document.createElement('script');

    script.async = true;
    script.src = this.props.src;
    script.onload = () => this.setState({
      loaded: true,
    });

    head.appendChild(script);
  }

  render() {
    return this.state.loaded ? this.props.children : null;
  }
}

const loadScriptDecorator = src => story => <Script src={src}>{story()}</Script>;

export default loadScriptDecorator;

@jhta
Copy link

jhta commented Aug 26, 2019

I created a public decorator to solve it:
https://www.npmjs.com/package/storybook-external-links

It also works for Vue.

@Koda-Pig
Copy link

Koda-Pig commented Nov 17, 2022

Leaving this snippet here for anyone who may have a similar need to load scripts per-story:

import React, { Component } from 'react';
import PropTypes from 'prop-types';

class Script extends Component {
  static propTypes = {
    src: PropTypes.string.isRequired,
  };

  state = {
    loaded: false,
  };

  componentWillMount() {
    const head = document.querySelector('head');
    const script = document.createElement('script');

    script.async = true;
    script.src = this.props.src;
    script.onload = () => this.setState({
      loaded: true,
    });

    head.appendChild(script);
  }

  render() {
    return this.state.loaded ? this.props.children : null;
  }
}

const loadScriptDecorator = src => story => <Script src={src}>{story()}</Script>;

export default loadScriptDecorator;

Thank you for sharing that snippet 🙏

I'm struggling to get it to work properly though. Could you please share an example of how to use that decorator in a Story?

@3mcd

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants