• 功能开关
    • 参考资料:

    功能开关

    使用Redux在React中实现Feature标记符

    1. // createFeatureFlaggedContainer.js
    2. import React from 'react';
    3. import { connect } from 'react-redux';
    4. import { isFeatureEnabled } from './reducers'
    5. export default function createFeatureFlaggedContainer({
    6. featureName,
    7. enabledComponent,
    8. disabledComponent
    9. }) {
    10. function FeatureFlaggedContainer({ isEnabled, ...props }) {
    11. const Component = isEnabled ? enabledComponent : disabledComponent;
    12. if (Component) {
    13. return <Component {...props} />;
    14. }
    15. // `disabledComponent` is optional property
    16. return null;
    17. }
    18. // Having `displayName` is very useful for debugging.
    19. FeatureFlaggedContainer.displayName = `FeatureFlaggedContainer(${ featureName })`;
    20. return connect((store) => {
    21. isEnabled: isFeatureEnabled(store, featureName)
    22. })(FeatureFlaggedContainer);
    23. }
    1. // EnabledFeature.js
    2. import { connect } from 'react-redux';
    3. import { isFeatureEnabled } from './reducers'
    4. function EnabledFeature({ isEnabled, children }) {
    5. if (isEnabled) {
    6. return children;
    7. }
    8. return null;
    9. }
    10. export default connect((store, { name }) => {
    11. isEnabled: isFeatureEnabled(store, name)
    12. })(EnabledFeature);
    1. // featureEnabled.js
    2. import createFeatureFlaggedContainer from './createFeatureFlaggedContainer'
    3. // Decorator for "Page" components.
    4. // usage: enabledFeature('unicorns')(UnicornsPage);
    5. export default function enabledFeature(featureName) {
    6. return (Component) => {
    7. return createFeatureFlaggedContainer({
    8. featureName,
    9. enabledComponent: Component,
    10. disabledComponent: PageNotFound, // 404 page or something similar
    11. });
    12. };
    13. };
    1. // features.js
    2. // This is quite simple reducer, containing only an array of features.
    3. // You can attach this data to a `currentUser` or similar reducer.
    4. // `BOOTSTAP` is global action, which contains the initial data for a page
    5. // Features access usually don't change during user usage of a page
    6. const BOOTSTAP = 'features/receive';
    7. export default function featuresReducer(state, { type, payload }) {
    8. if (type === BOOTSTAP) {
    9. return payload.features || [];
    10. }
    11. return state || [];
    12. }
    13. export function isFeatureEnabled(features, featureName) {
    14. return features.indexOf(featureName) !== -1;
    15. }
    1. // reducers.js
    2. // This is your main reducer.js file
    3. import { combineReducers } from 'redux';
    4. import features, { isFeatureEnabled as isFeatureEnabledSelector } from './features';
    5. // ...other reducers
    6. export default combineReducers({
    7. features
    8. // ...other reducers
    9. });
    10. // This is the important part, access to `features` reducer should only happens
    11. // via this selector.
    12. // Then you can always change where/how the features are stored.
    13. export function isFeatureEnabled({ features }, featureName) {
    14. return isFeatureEnabledSelector(features, featureName);
    15. }

    参考资料:

    • Feature flags in React
    • Gist