Skip to content

Request of feature flag immediately after ldClient.on('ready') returns undefined #81

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

Closed
miymiy opened this issue Apr 24, 2018 · 3 comments

Comments

@miymiy
Copy link

miymiy commented Apr 24, 2018

We have a wrapper feature toggle component wraps around ldClient. It is basically a copy of ld-redux code with some minor changes. Upon initialisation, the following event occurs

window.ldClient.on('ready', () => { reduxStore.dispatch(setLDReady()); });

This action triggers the feature toggle component update

componentWillReceiveProps(newProps) {
    if (this.isLDReady()) {
        this.initialise();

        if (!isEqual(newProps.userData, this.props.userData)) {
            this.updateUser();
        }
    }
}

in the function initialise feature flag query is fired
ldClient.variation(flagNameInLd, ldDefaultValues[flagNameInLd])

And it always returns undefined - checking dev console in Launch Darkly it also shows undefined as a value.

The above code works if I put a setTimeout wrapper around reduxStore.dispatch(setLDReady()); and force a 100ms delay.

My question is, when ldClient emits the ready event, is it really ready for features to be queried? or should we be using other events?

@apucacao
Copy link
Contributor

Hi @miymiy ,

Yes, when the ready event is emitted, the SDK is ready to give you flag values.

Could you share your initialization code? Also, do you see any errors in the browser console?

@miymiy
Copy link
Author

miymiy commented Apr 25, 2018

Hey @apucacao ,

Thanks for responding! Here are the code snippets (think majority of it is a copy from ldRedux). There were no errors in console.

On init

export default (clientSideId, reduxStore, user) => {
    let newUser = user;
    if (!newUser) {
        newUser = createUser();
    }

    window.ldClient = ldClient.initialize(clientSideId, newUser);
    window.ldClient.user = newUser;
    window.ldClient.on('ready', () => {
        reduxStore.dispatch(setLDReady());
    });
};

setLDReady sets the state.LD.isLDReady flag to true. And then the wrapper component


export default (WrappedComponent) => {
    class WithFeatureFlags extends Component {
        constructor(props) {
            super(props);
            this.initialise = this.initialise.bind(this);
            this.updateUser = this.updateUser.bind(this);
            this.isLDReady = this.isLDReady.bind(this);
            this.subscribeToFlagChanges = this.subscribeToFlagChanges.bind(this);
            this.state = {
                initialised: false,
            };
        }

        componentDidMount() {
            if (this.isLDReady()) {
                this.initialise();
                this.updateUser();
            }
        }

        componentWillReceiveProps(newProps) {
            if (this.isLDReady()) {
                this.initialise();

                if (!isEqual(newProps.userData, this.props.userData)) {
                    this.updateUser();
                }
            }
        }

        isLDReady() {
            const state = this.context.store.getState();

            return state.LD.isLDReady;
        }

        subscribeToFlagChanges(flagNameInLd, flagNameInState) {
            const { dispatch } = this.context.store;

            ldClient.on(`change:${flagNameInLd}`, (current) => {
                const newFlagValues = {};
                newFlagValues[flagNameInState] = current;

                dispatch(setFlags(newFlagValues));
            });
        }

        initialise() {
            if (this.state.initialised) {
                return;
            }

            const { dispatch } = this.context.store;
            const flagValues = {};

            this.props.flags.forEach((flagNameInLd) => {
                const flagNameInState = camelCase(flagNameInLd);
                flagValues[flagNameInState] =
                    ldClient.variation(flagNameInLd, ldDefaultValues[flagNameInLd]);
                /*****************************
                  ldClient returns undefined for the value: flagNameInLd
                *****************************/
                this.subscribeToFlagChanges(flagNameInLd, flagNameInState);
            });

            dispatch(setFlags(flagValues));

            this.setState({
                initialised: true,
            });
        }

        updateUser() {
            const currentUser = window.ldClient.user;
            const ldCustom = { ...currentUser.custom, ...this.props.userData.custom };
            const ldUser = { ...currentUser, ...this.props.userData };
            ldUser.custom = ldCustom;

            window.ldClient.identify(ldUser);
            window.ldClient.user = ldUser;
        }

        render() {
            const state = this.context.store.getState();
            const flagValues = getFlags(state, this.props.flags);

            return <WrappedComponent {...this.props} flagValues={flagValues} />;
        }
    }

    WithFeatureFlags.propTypes = {
        userData: PropTypes.ldUser,
        // eslint-disable-next-line react/forbid-prop-types
        flags: PropTypes.arrayOf(PropTypes.string).isRequired,
    };

    WithFeatureFlags.contextTypes = {
        store: PropTypes.object.isRequired,
    };

    return WithFeatureFlags;
};

eli-darkly added a commit that referenced this issue Jun 22, 2018
add unit test for customer-contributed fix to localstorage logic
@eli-darkly
Copy link
Contributor

Hi - sorry we did not check in again on this issue earlier. Your code sample looked good as far as we could tell, so it wasn't clear what was going on. I do see however that ld-redux seems to have changed significantly since then, so I'm wondering whether you are using the new version and if so, have you still seen any similar problems?

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

3 participants