Coder Social home page Coder Social logo

extremely-simple-flux-demo's Introduction

This demo helps you learn Flux architecture. It is inspired by Andrew Ray's great article Flux For Stupid People.

What is Flux?

Flux, invented by Facebook, is an architecture pattern for building client-side web applications.

It is similar to MVC architecture, but Flux's concept is much clearer than MVC's, and easier to learn.

How to Play?

Install the demo.

$ git clone [email protected]:ruanyf/extremely-simple-flux-demo.git
$ cd extremely-simple-flux-demo && npm install
$ npm start

Visit http://127.0.0.1:8080 with your browser.

You should see a button. Click it. That's all.

Core Concepts

According to Flux, an application should be divided into four parts.

  • Views: the UI layer
  • Actions: messages sent from Views (e.g. mouseClick)
  • Dispatcher: a place receiving actions, and calling callbacks
  • Stores: a place managing the Application's state, and reminding Views to update

The key feature of the Flux architecture is "one way" (unidirectional) data flow.

  1. User interacts with Views
  2. Views propagate an Action triggered by user
  3. Dispatcher receives the Action and updates the Store
  4. Store emits a "change" event
  5. Views respond to the "change" event and update itself

Don't get it? Take it easy. I will give you the details soon.

Demo Details

Now let us follow the demo to learn Flux.

First of all, Flux is usually used with React. So your familiarity with React is assumed. If not, I prepared a React tutorial for you.

Views

Our demo application's index.jsx has only one component.

// index.jsx
var React = require('react');
var ReactDOM = require('react-dom');
var MyButtonController = require('./components/MyButtonController');

ReactDOM.render(
  <MyButtonController/>,
  document.querySelector('#example')
);

In the above code, you might notice our component's name isn't MyButton, but MyButtonController. Why?

Because I use React's controller view pattern here. A controller view component holds all states, then passes this data to its descendants. MyButtonController's source code is simple.

// components/MyButtonController.jsx
var React = require('react');
var ButtonActions = require('../actions/ButtonActions');
var MyButton = require('./MyButton');

var MyButtonController = React.createClass({
  createNewItem: function (event) {
    ButtonActions.addNewItem('new item');
  },

  render: function() {
    return <MyButton
      onClick={this.createNewItem}
    />;
  }
});

module.exports = MyButtonController;

In the above code, MyButtonController puts its data into UI component MyButton's properties. MyButton's source code is even simpler.

// components/MyButton.jsx
var React = require('react');

var MyButton = function(props) {
  return <div>
    <button onClick={props.onClick}>New Item</button>
  </div>;
};

module.exports = MyButton;

In the above code, you may find MyButton is a pure component (meaning stateless), which is really the biggest advantage of the controll view pattern.

Here, the logic of our application is when user clicks MyButton, the this.createNewItem method will be called. It sends an action to Dispatcher.

// components/MyButtonController.jsx

  // ...
  createNewItem: function (event) {
    ButtonActions.addNewItem('new item');
  }

In the above code, calling the createNewItem method will trigger an addNewItem action.

What is an Action?

An action is an object which has some properties to carry data and an actionType property to identify the action type.

In our demo, the ButtonActions object is the place we hold all actions.

// actions/ButtonActions.js
var AppDispatcher = require('../dispatcher/AppDispatcher');

var ButtonActions = {
  addNewItem: function (text) {
    AppDispatcher.dispatch({
      actionType: 'ADD_NEW_ITEM',
      text: text
    });
  },
};

In the above code, the ButtonActions.addNewItem method will use AppDispatcher to dispatch the ADD_NEW_ITEM action to the Stores.

Dispatcher

The Dispatcher transfers the Actions to the Stores. It is essentially an event hub for your application's Views. There is only one global Dispatcher.

We use the Facebook official Dispatcher Library, and write a AppDispatcher.js as our application's dispatcher instance.

// dispatcher/AppDispatcher.js
var Dispatcher = require('flux').Dispatcher;
module.exports = new Dispatcher();

AppDispatcher.register() is used for registering a callback for actions.

// dispatcher/AppDispatcher.js
var ListStore = require('../stores/ListStore');

AppDispatcher.register(function (action) {
  switch(action.actionType) {
    case 'ADD_NEW_ITEM':
      ListStore.addNewItemHandler(action.text);
      ListStore.emitChange();
      break;
    default:
      // no op
  }
})

In the above code, when receiving the ADD_NEW_ITEM action, the callback will operate the ListStore.

Please keep in mind, Dispatcher has no real intelligence on its own — it is a simple mechanism for distributing the actions to the stores.

Stores

The Stores contain the application state. Their role is somewhat similar to a model in a traditional MVC.

In this demo, we have a ListStore to store data.

// stores/ListStore.js
var ListStore = {
  items: [],

  getAll: function() {
    return this.items;
  },

  addNewItemHandler: function (text) {
    this.items.push(text);
  },

  emitChange: function () {
    this.emit('change');
  }
};

module.exports = ListStore;

In the above code, ListStore.items is used for holding items, ListStore.getAll() for getting all these items, and ListStore.emitChange() for emitting an event to the Views.

The Stores should implement an event interface as well. Since after receiving an action from the Dispatcher, the Stores should emit a change event to tell the Views that a change to the data layer has occurred.

// stores/ListStore.js
var EventEmitter = require('events').EventEmitter;
var assign = require('object-assign');

var ListStore = assign({}, EventEmitter.prototype, {
  items: [],

  getAll: function () {
    return this.items;
  },

  addNewItemHandler: function (text) {
    this.items.push(text);
  },

  emitChange: function () {
    this.emit('change');
  },

  addChangeListener: function(callback) {
    this.on('change', callback);
  },

  removeChangeListener: function(callback) {
    this.removeListener('change', callback);
  }
});

In the above code, ListStore inheritances EventEmitter.prototype, so you can use ListStore.on() and ListStore.emit().

After updated(this.addNewItemHandler()), the Stores emit an event(this.emitChange()) declaring that their state has changed, so the Views may query the new state and update themselves.

Views, again

Now, we come back to the Views for implementing an callback for listening the Store's change event.

// components/MyButtonController.jsx
var React = require('react');
var ListStore = require('../stores/ListStore');
var ButtonActions = require('../actions/ButtonActions');
var MyButton = require('./MyButton');

var MyButtonController = React.createClass({
  getInitialState: function () {
    return {
      items: ListStore.getAll()
    };
  },

  componentDidMount: function() {
    ListStore.addChangeListener(this._onChange);
  },

  componentWillUnmount: function() {
    ListStore.removeChangeListener(this._onChange);
  },

  _onChange: function () {
    this.setState({
      items: ListStore.getAll()
    });
  },

  createNewItem: function (event) {
    ButtonActions.addNewItem('new item');
  },

  render: function() {
    return <MyButton
      items={this.state.items}
      onClick={this.createNewItem}
    />;
  }
});

In the above code, you could see when MyButtonController finds out the Store's change event occurred, it calls this._onChange to update the component's state, then trigger a re-render.

// components/MyButton.jsx
var React = require('react');

var MyButton = function(props) {
  var items = props.items;
  var itemHtml = items.map(function (listItem, i) {
    return <li key={i}>{listItem}</li>;
  });

  return <div>
    <ul>{itemHtml}</ul>
    <button onClick={props.onClick}>New Item</button>
  </div>;
};

module.exports = MyButton;

License

MIT

extremely-simple-flux-demo's People

Contributors

printerscanner avatar ralphite avatar ruanyf avatar totorofn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

extremely-simple-flux-demo's Issues

npm start出错

root@test:~/extremely-simple-flux-demo# npm start

[email protected] start /root/extremely-simple-flux-demo
webpack-dev-server --progress
0% compilehttp://localhost:8080/webpack-dev-server/
webpack result is served from /
content is served from /root/extremely-simple-flux 95% emitHash: 11cdeba589a6a51eb71b
Version: webpack 1.12.14
Time: 3263ms
Asset Size Chunks Chunk Names
bundle.js 697 kB 0, 1 [emitted] main
init.js 3.51 kB 1 [emitted] init.js
chunk {0} bundle.js (main) 664 kB {1} [rendered]
[0] ./index.jsx 243 bytes {0} [built]
[1] .//react/react.js 56 bytes {0} [built]
[2] ./
/react/lib/React.js 1.49 kB {0} [built]
[3] .//react/lib/ReactDOM.js 3.71 kB {0} [built]
4/
/node-libs-browser//process/browser.js 2.06 kB {0} [built]
[5] ./
/react/lib/ReactCurrentOwner.js 653 bytes {0} [built]
[6] .//react/lib/ReactDOMTextComponent.js 4.32 kB {0} [built]
[7] ./
/react/lib/DOMChildrenOperations.js 5 kB {0} [built]
[8] .//react/lib/Danger.js 6.96 kB {0} [built]
[9] ./
/react//fbjs/lib/ExecutionEnvironment.js 1.09 kB {0} [built]
[10] ./
/react//fbjs/lib/createNodesFromMarkup.js 2.71 kB {0} [built]
[11] ./
/react//fbjs/lib/createArrayFromMixed.js 2.36 kB {0} [built]
[12] ./
/react//fbjs/lib/toArray.js 1.98 kB {0} [built]
[13] ./
/react//fbjs/lib/invariant.js 1.51 kB {0} [built]
[14] ./
/react//fbjs/lib/getMarkupWrap.js 3.06 kB {0} [built]
[15] ./
/react//fbjs/lib/emptyFunction.js 1.09 kB {0} [built]
[16] ./
/react/lib/ReactMultiChildUpdateTypes.js 861 bytes {0} [built]
[17] .//react//fbjs/lib/keyMirror.js 1.27 kB {0} [built]
[18] .//react/lib/ReactPerf.js 2.51 kB {0} [built]
[19] ./
/react/lib/setInnerHTML.js 3.35 kB {0} [built]
[20] .//react/lib/setTextContent.js 1.2 kB {0} [built]
[21] ./
/react/lib/escapeTextContentForBrowser.js 849 bytes {0} [built]
[22] .//react/lib/DOMPropertyOperations.js 7.88 kB {0} [built]
[23] ./
/react/lib/DOMProperty.js 9.57 kB {0} [built]
[24] .//react/lib/quoteAttributeValueForBrowser.js 746 bytes {0} [built]
[25] ./
/react//fbjs/lib/warning.js 1.77 kB {0} [built]
[26] ./
/react/lib/ReactComponentBrowserEnvironment.js 1.26 kB {0} [built]
[27] .//react/lib/ReactDOMIDOperations.js 3.29 kB {0} [built]
[28] ./
/react/lib/ReactMount.js 36.8 kB {0} [built]
[29] .//react/lib/ReactBrowserEventEmitter.js 12.4 kB {0} [built]
[30] ./
/react/lib/EventConstants.js 2.04 kB {0} [built]
[31] .//react/lib/EventPluginHub.js 9.22 kB {0} [built]
[32] ./
/react/lib/EventPluginRegistry.js 8.41 kB {0} [built]
[33] .//react/lib/EventPluginUtils.js 6.79 kB {0} [built]
[34] ./
/react/lib/ReactErrorUtils.js 2.27 kB {0} [built]
[35] .//react/lib/accumulateInto.js 1.74 kB {0} [built]
[36] ./
/react/lib/forEachAccumulated.js 893 bytes {0} [built]
[37] .//react/lib/ReactEventEmitterMixin.js 1.3 kB {0} [built]
[38] ./
/react/lib/ViewportMetrics.js 638 bytes {0} [built]
[39] .//react/lib/Object.assign.js 1.26 kB {0} [built]
[40] ./
/react/lib/isEventSupported.js 1.97 kB {0} [built]
[41] .//react/lib/ReactDOMFeatureFlags.js 458 bytes {0} [built]
[42] ./
/react/lib/ReactElement.js 8.07 kB {0} [built]
[43] .//react/lib/canDefineProperty.js 629 bytes {0} [built]
[44] ./
/react/lib/ReactEmptyComponentRegistry.js 1.38 kB {0} [built]
[45] .//react/lib/ReactInstanceHandles.js 10.6 kB {0} [built]
[46] ./
/react/lib/ReactRootIndex.js 723 bytes {0} [built]
[47] .//react/lib/ReactInstanceMap.js 1.25 kB {0} [built]
[48] ./
/react/lib/ReactMarkupChecksum.js 1.39 kB {0} [built]
[49] .//react/lib/adler32.js 1.2 kB {0} [built]
[50] ./
/react/lib/ReactReconciler.js 3.55 kB {0} [built]
[51] .//react/lib/ReactRef.js 2.34 kB {0} [built]
[52] ./
/react/lib/ReactOwner.js 3.45 kB {0} [built]
[53] .//react/lib/ReactUpdateQueue.js 10.9 kB {0} [built]
[54] ./
/react/lib/ReactUpdates.js 8.54 kB {0} [built]
[55] .//react/lib/CallbackQueue.js 2.44 kB {0} [built]
[56] ./
/react/lib/PooledClass.js 3.55 kB {0} [built]
[57] .//react/lib/Transaction.js 9.55 kB {0} [built]
[58] ./
/react//fbjs/lib/emptyObject.js 482 bytes {0} [built]
[59] ./
/react//fbjs/lib/containsNode.js 1.43 kB {0} [built]
[60] ./
/react//fbjs/lib/isTextNode.js 628 bytes {0} [built]
[61] ./
/react//fbjs/lib/isNode.js 712 bytes {0} [built]
[62] ./
/react/lib/instantiateReactComponent.js 4.52 kB {0} [built]
[63] .//react/lib/ReactCompositeComponent.js 27.5 kB {0} [built]
[64] ./
/react/lib/ReactComponentEnvironment.js 1.67 kB {0} [built]
[65] .//react/lib/ReactPropTypeLocations.js 549 bytes {0} [built]
[66] ./
/react/lib/ReactPropTypeLocationNames.js 611 bytes {0} [built]
[67] .//react/lib/shouldUpdateReactComponent.js 1.49 kB {0} [built]
[68] ./
/react/lib/ReactEmptyComponent.js 1.68 kB {0} [built]
[69] .//react/lib/ReactNativeComponent.js 3.02 kB {0} [built]
[70] ./
/react/lib/validateDOMNesting.js 13.1 kB {0} [built]
[71] .//react/lib/ReactDefaultInjection.js 3.99 kB {0} [built]
[72] ./
/react/lib/BeforeInputEventPlugin.js 14.9 kB {0} [built]
[73] .//react/lib/EventPropagators.js 5.22 kB {0} [built]
[74] ./
/react/lib/FallbackCompositionState.js 2.49 kB {0} [built]
[75] .//react/lib/getTextContentAccessor.js 994 bytes {0} [built]
[76] ./
/react/lib/SyntheticCompositionEvent.js 1.16 kB {0} [built]
[77] .//react/lib/SyntheticEvent.js 5.79 kB {0} [built]
[78] ./
/react/lib/SyntheticInputEvent.js 1.15 kB {0} [built]
[79] .//react//fbjs/lib/keyOf.js 1.11 kB {0} [built]
[80] .//react/lib/ChangeEventPlugin.js 11.5 kB {0} [built]
[81] ./
/react/lib/getEventTarget.js 930 bytes {0} [built]
[82] .//react/lib/isTextInputElement.js 1.03 kB {0} [built]
[83] ./
/react/lib/ClientReactRootIndex.js 551 bytes {0} [built]
[84] .//react/lib/DefaultEventPluginOrder.js 1.26 kB {0} [built]
[85] ./
/react/lib/EnterLeaveEventPlugin.js 3.9 kB {0} [built]
[86] .//react/lib/SyntheticMouseEvent.js 2.2 kB {0} [built]
[87] ./
/react/lib/SyntheticUIEvent.js 1.64 kB {0} [built]
[88] .//react/lib/getEventModifierState.js 1.3 kB {0} [built]
[89] ./
/react/lib/HTMLDOMPropertyConfig.js 7.63 kB {0} [built]
[90] .//react/lib/ReactBrowserComponentMixin.js 1.15 kB {0} [built]
[91] ./
/react/lib/findDOMNode.js 2.17 kB {0} [built]
[92] .//react/lib/ReactDefaultBatchingStrategy.js 1.92 kB {0} [built]
[93] ./
/react/lib/ReactDOMComponent.js 36.9 kB {0} [built]
[94] .//react/lib/AutoFocusUtils.js 816 bytes {0} [built]
[95] ./
/react//fbjs/lib/focusNode.js 725 bytes {0} [built]
[96] ./
/react/lib/CSSPropertyOperations.js 5.71 kB {0} [built]
[97] .//react/lib/CSSProperty.js 3.5 kB {0} [built]
[98] ./
/react//fbjs/lib/camelizeStyleName.js 1.03 kB {0} [built]
[99] ./
/react//fbjs/lib/camelize.js 729 bytes {0} [built]
[100] ./
/react/lib/dangerousStyleValue.js 1.93 kB {0} [built]
[101] .//react//fbjs/lib/hyphenateStyleName.js 1 kB {0} [built]
[102] .//react//fbjs/lib/hyphenate.js 822 bytes {0} [built]
[103] .//react//fbjs/lib/memoizeStringOnly.js 778 bytes {0} [built]
[104] .//react/lib/ReactDOMButton.js 1.15 kB {0} [built]
[105] ./
/react/lib/ReactDOMInput.js 5.74 kB {0} [built]
[106] .//react/lib/LinkedValueUtils.js 5.18 kB {0} [built]
[107] ./
/react/lib/ReactPropTypes.js 12.3 kB {0} [built]
[108] .//react/lib/getIteratorFn.js 1.17 kB {0} [built]
[109] ./
/react/lib/ReactDOMOption.js 2.82 kB {0} [built]
[110] .//react/lib/ReactChildren.js 5.83 kB {0} [built]
[111] ./
/react/lib/traverseAllChildren.js 6.9 kB {0} [built]
[112] .//react/lib/ReactDOMSelect.js 6.11 kB {0} [built]
[113] ./
/react/lib/ReactDOMTextarea.js 4.35 kB {0} [built]
[114] .//react/lib/ReactMultiChild.js 14.7 kB {0} [built]
[115] ./
/react/lib/ReactChildReconciler.js 4.52 kB {0} [built]
[116] .//react/lib/flattenChildren.js 1.65 kB {0} [built]
[117] ./
/react//fbjs/lib/shallowEqual.js 1.28 kB {0} [built]
[118] ./
/react/lib/ReactEventListener.js 7.51 kB {0} [built]
[119] .//react//fbjs/lib/EventListener.js 2.65 kB {0} [built]
[120] .//react//fbjs/lib/getUnboundedScrollPosition.js 1.09 kB {0} [built]
[121] .//react/lib/ReactInjection.js 1.37 kB {0} [built]
[122] ./
/react/lib/ReactClass.js 27.8 kB {0} [built]
[123] .//react/lib/ReactComponent.js 5.04 kB {0} [built]
[124] ./
/react/lib/ReactNoopUpdateQueue.js 3.94 kB {0} [built]
[125] .//react/lib/ReactReconcileTransaction.js 4.58 kB {0} [built]
[126] ./
/react/lib/ReactInputSelection.js 4.32 kB {0} [built]
[127] .//react/lib/ReactDOMSelection.js 6.83 kB {0} [built]
[128] ./
/react/lib/getNodeForCharacterOffset.js 1.66 kB {0} [built]
[129] .//react//fbjs/lib/getActiveElement.js 924 bytes {0} [built]
[130] .//react/lib/SelectEventPlugin.js 6.71 kB {0} [built]
[131] ./
/react/lib/ServerReactRootIndex.js 868 bytes {0} [built]
[132] .//react/lib/SimpleEventPlugin.js 17.4 kB {0} [built]
[133] ./
/react/lib/SyntheticClipboardEvent.js 1.23 kB {0} [built]
[134] .//react/lib/SyntheticFocusEvent.js 1.12 kB {0} [built]
[135] ./
/react/lib/SyntheticKeyboardEvent.js 2.76 kB {0} [built]
[136] .//react/lib/getEventCharCode.js 1.56 kB {0} [built]
[137] ./
/react/lib/getEventKey.js 2.93 kB {0} [built]
[138] .//react/lib/SyntheticDragEvent.js 1.13 kB {0} [built]
[139] ./
/react/lib/SyntheticTouchEvent.js 1.33 kB {0} [built]
[140] .//react/lib/SyntheticWheelEvent.js 1.99 kB {0} [built]
[141] ./
/react/lib/SVGDOMPropertyConfig.js 3.8 kB {0} [built]
[142] .//react/lib/ReactDefaultPerf.js 8.63 kB {0} [built]
[143] ./
/react/lib/ReactDefaultPerfAnalysis.js 5.79 kB {0} [built]
[144] .//react//fbjs/lib/performanceNow.js 844 bytes {0} [built]
[145] .//react//fbjs/lib/performance.js 612 bytes {0} [built]
[146] .//react/lib/ReactVersion.js 379 bytes {0} [built]
[147] ./
/react/lib/renderSubtreeIntoContainer.js 463 bytes {0} [built]
[148] .//react/lib/ReactDOMServer.js 766 bytes {0} [built]
[149] ./
/react/lib/ReactServerRendering.js 3.3 kB {0} [built]
[150] .//react/lib/ReactServerBatchingStrategy.js 673 bytes {0} [built]
[151] ./
/react/lib/ReactServerRenderingTransaction.js 2.3 kB {0} [built]
[152] .//react/lib/ReactIsomorphic.js 2.05 kB {0} [built]
[153] ./
/react/lib/ReactDOMFactories.js 3.36 kB {0} [built]
[154] .//react/lib/ReactElementValidator.js 10.8 kB {0} [built]
[155] ./
/react//fbjs/lib/mapObject.js 1.47 kB {0} [built]
[156] ./
/react/lib/onlyChild.js 1.21 kB {0} [built]
[157] .//react/lib/deprecated.js 1.77 kB {0} [built]
[158] ./
/react-dom/index.js 63 bytes {0} [built]
[159] ./components/MyButtonController.jsx 892 bytes {0} [built]
[160] ./stores/ListStore.js 636 bytes {0} [built]
161//node-libs-browser//events/events.js 8.19 kB {0} [built]
[162] .//object-assign/index.js 896 bytes {0} [built]
[163] ./actions/ButtonActions.js 269 bytes {0} [built]
[164] ./dispatcher/AppDispatcher.js 403 bytes {0} [built]
[165] ./
/flux/index.js 363 bytes {0} [built]
[166] .//flux/lib/Dispatcher.js 7.36 kB {0} [built]
[167] ./
/flux/lib/invariant.js 1.51 kB {0} [built]
[168] ./components/MyButton.jsx 407 bytes {0} [built]
chunk {1} init.js (init.js) 0 bytes [rendered]
webpack: bundle is now VALID.

/root/extremely-simple-flux-demo/node_modules/open-browser-webpack-plugin/index.js:45
if (err) throw err;
^
Error: Command failed: /root/extremely-simple-flux-demo/node_modules/open-browser-webpack-plugin/node_modules/open/vendor/xdg-open: 1: /root/extremely-simple-flux-demo/node_modules/open-browser-webpack-plugin/node_modules/open/vendor/xdg-open: xdg-mime: not found
xdg-open: no method available for opening 'http://localhost:8080'

at ChildProcess.exithandler (child_process.js:637:15)
at ChildProcess.EventEmitter.emit (events.js:98:17)
at maybeClose (child_process.js:743:16)
at Socket.<anonymous> (child_process.js:956:11)
at Socket.EventEmitter.emit (events.js:95:17)
at Pipe.close (net.js:466:12)

npm ERR! weird error 8
npm WARN This failure might be due to the use of legacy binary "node"
npm WARN For further explanations, please read
/usr/share/doc/nodejs/README.Debian

npm ERR! not ok code 0

做到npm start那个步骤出错了,麻烦帮我看一下是什么问题。

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.