[React] 10 - Tutorial: router
在安装react-router的时候加上一个5系列的版本号的,6版本api确实发生改变了,却不向下兼容,官方有点过分~
意识到不妙的我赶紧去翻了翻react router的文档,发现react router早就在21年底就偷偷升级到了v6且变更极大。
Ref: REACT JS TUTORIAL #6 - React Router & Intro to Single Page Apps with React JS
Ref: REACT JS TUTORIAL #7 - React Router Params & Queries
Ref: REACT JS TUTORIAL #8 - React Inline Styles & Component Arrays
Ref: react 技巧 #3 react-router 教程 part 1
Ref: react 技巧 #4 react-router 教程 part 2
- 预 - 热 -
安装: react-router
参考:npm使用教程,安装方法总结如下。
==npm安装== npm install --save react-router npm install --save react-router-dom
==yarn安装== yarn add react-router yarn add react-router-dom
==也可以使用React-Router CDN库== <script src="https://unpkg.com/react-router/umd/ReactRouter.min.js"></script>
-S
就是--save
的简写,就行npm 默认一个start 的字段,将包的名称及版本号放在 dependencies 里面。
-D 就是--save-dev 这样安装的包的名称及版本号就会存在package.json的 devDependencies 这个里面。
package.json { "name" : "react-tutorials", "version" : "0.0.0", "description" : "", "main" : "webpack.config.js", "dependencies" : { "babel-core" : "^6.17.0", "babel-loader": "^6.2.0", "babel-plugin-add-module-exports": "^0.1.2", "babel-plugin-react-html-attrs ": "^2.0.0", "babel-plugin-transform-class-properties" : "^6.3.13", "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-preset-es2015" : "^6.3.13", "babel-preset-react" : "^6.3.13", "babel-preset-stage-0": "^6.3.13", "history" : "^1.17.0", "react" : "^0.14.6", "react-dom" : "^0.14.6", "react-router": "^1.0.3", // <---- 其实就是自动帮你写了,不用手动添加了 "webpack" : "^1.12.9", "webpack-dev-server": "^1.14.1" }, "devDependencies": { "webpack-cli": "^2.1.3" }, "scripts": { "dev": "webpack-dev-server --content-base src --inline --hot" }, "author": "", "license": "ISC" }
lolo@lolo-UX303UB$ npm run dev
unsw@unsw-UX303UB$ npm run dev > react-tutorials@0.0.0 dev /media/unsw/CloudStorage/Linux-pan/ExtendedTmpSpace/Android-Workplace/android-and-ml/React-Native/demo-react/react-js-tutorials/2-react-router > webpack-dev-server --content-base src --inline --hot http://localhost:8080/ webpack result is served from / content is served from /media/unsw/CloudStorage/Linux-pan/ExtendedTmpSpace/Android-Workplace/android-and-ml/React-Native/demo-react/react-js-tutorials/2-react-router/src Hash: d1bf073bfd493e36aea9 Version: webpack 1.15.0 Time: 3176ms Asset Size Chunks Chunk Names client.min.js 2.8 MB 0 [emitted] main chunk {0} client.min.js (main) 1.02 MB [rendered] [0] multi main 52 bytes {0} [built] [1] (webpack)-dev-server/client?http://localhost:8080 4.16 kB {0} [built] [2] ./~/url/url.js 23.3 kB {0} [built] [3] ./~/url/~/punycode/punycode.js 14.6 kB {0} [built] [4] (webpack)/buildin/module.js 251 bytes {0} [built] [5] ./~/url/util.js 314 bytes {0} [built] [6] ./~/querystring/index.js 127 bytes {0} [built] [7] ./~/querystring/decode.js 2.4 kB {0} [built] [8] ./~/querystring/encode.js 2.09 kB {0} [built] [9] (webpack)-dev-server/~/strip-ansi/index.js 161 bytes {0} [built] [10] (webpack)-dev-server/~/ansi-regex/index.js 135 bytes {0} [built] [11] (webpack)-dev-server/client/socket.js 897 bytes {0} [built] [12] ./~/sockjs-client/lib/entry.js 244 bytes {0} [built] [13] ./~/sockjs-client/lib/transport-list.js 613 bytes {0} [built] [14] ./~/sockjs-client/lib/transport/websocket.js 2.72 kB {0} [built] [15] ./~/process/browser.js 5.42 kB {0} [built] [16] ./~/sockjs-client/lib/utils/event.js 2 kB {0} [built] [17] ./~/sockjs-client/lib/utils/random.js 746 bytes {0} [built] [18] ./~/sockjs-client/lib/utils/browser-crypto.js 438 bytes {0} [built] [19] ./~/sockjs-client/lib/utils/url.js 975 bytes {0} [built] [20] ./~/url-parse/index.js 11.5 kB {0} [built] [21] ./~/requires-port/index.js 753 bytes {0} [built] [22] ./~/url-parse/~/querystringify/index.js 1.58 kB {0} [built] [23] ./~/debug/src/browser.js 4.73 kB {0} [built] [24] ./~/debug/src/debug.js 4.39 kB {0} [built] [25] ./~/ms/index.js 2.76 kB {0} [built] [26] ./~/inherits/inherits_browser.js 672 bytes {0} [built] [27] ./~/sockjs-client/lib/event/emitter.js 1.27 kB {0} [built] [28] ./~/sockjs-client/lib/event/eventtarget.js 1.85 kB {0} [built] [29] ./~/sockjs-client/lib/transport/browser/websocket.js 210 bytes {0} [built] [30] ./~/sockjs-client/lib/transport/xhr-streaming.js 1.25 kB {0} [built] [31] ./~/sockjs-client/lib/transport/lib/ajax-based.js 1.31 kB {0} [built] [32] ./~/sockjs-client/lib/transport/lib/sender-receiver.js 1.18 kB {0} [built] [33] ./~/sockjs-client/lib/transport/lib/buffered-sender.js 2.3 kB {0} [built] [34] ./~/sockjs-client/lib/transport/lib/polling.js 1.32 kB {0} [built] [35] ./~/sockjs-client/lib/transport/receiver/xhr.js 1.58 kB {0} [built] [36] ./~/sockjs-client/lib/transport/sender/xhr-cors.js 343 bytes {0} [built] [37] ./~/sockjs-client/lib/transport/browser/abstract-xhr.js 4.8 kB {0} [built] [38] ./~/sockjs-client/lib/transport/sender/xhr-local.js 352 bytes {0} [built] [39] ./~/sockjs-client/lib/utils/browser.js 560 bytes {0} [built] [40] ./~/sockjs-client/lib/transport/xdr-streaming.js 984 bytes {0} [built] [41] ./~/sockjs-client/lib/transport/sender/xdr.js 2.46 kB {0} [built] [42] ./~/sockjs-client/lib/transport/eventsource.js 766 bytes {0} [built] [43] ./~/sockjs-client/lib/transport/receiver/eventsource.js 1.58 kB {0} [built] [44] ./~/sockjs-client/lib/transport/browser/eventsource.js 37 bytes {0} [built] [45] ./~/sockjs-client/lib/transport/lib/iframe-wrap.js 981 bytes {0} [built] [46] ./~/sockjs-client/lib/transport/iframe.js 3.83 kB {0} [built] [47] ./~/json3/lib/json3.js 43.3 kB {0} [built] [48] (webpack)/buildin/amd-options.js 43 bytes {0} [built] [49] ./~/sockjs-client/lib/version.js 26 bytes {0} [built] [50] ./~/sockjs-client/lib/utils/iframe.js 5.03 kB {0} [built] [51] ./~/sockjs-client/lib/utils/object.js 532 bytes {0} [built] [52] ./~/sockjs-client/lib/transport/htmlfile.js 710 bytes {0} [built] [53] ./~/sockjs-client/lib/transport/receiver/htmlfile.js 2.2 kB {0} [built] [54] ./~/sockjs-client/lib/transport/xhr-polling.js 894 bytes {0} [built] [55] ./~/sockjs-client/lib/transport/xdr-polling.js 712 bytes {0} [built] [56] ./~/sockjs-client/lib/transport/jsonp-polling.js 1.02 kB {0} [built] [57] ./~/sockjs-client/lib/transport/receiver/jsonp.js 5.57 kB {0} [built] [58] ./~/sockjs-client/lib/transport/sender/jsonp.js 2.46 kB {0} [built] [59] ./~/sockjs-client/lib/main.js 11.9 kB {0} [built] [60] ./~/sockjs-client/lib/shims.js 17.2 kB {0} [built] [61] ./~/sockjs-client/lib/utils/escape.js 2.36 kB {0} [built] [62] ./~/sockjs-client/lib/utils/transport.js 1.35 kB {0} [built] [63] ./~/sockjs-client/lib/utils/log.js 450 bytes {0} [built] [64] ./~/sockjs-client/lib/event/event.js 477 bytes {0} [built] [65] ./~/sockjs-client/lib/location.js 177 bytes {0} [built] [66] ./~/sockjs-client/lib/event/close.js 295 bytes {0} [built] [67] ./~/sockjs-client/lib/event/trans-message.js 292 bytes {0} [built] [68] ./~/sockjs-client/lib/info-receiver.js 2.22 kB {0} [built] [69] ./~/sockjs-client/lib/transport/sender/xhr-fake.js 456 bytes {0} [built] [70] ./~/sockjs-client/lib/info-iframe.js 1.52 kB {0} [built] [71] ./~/sockjs-client/lib/info-iframe-receiver.js 791 bytes {0} [built] [72] ./~/sockjs-client/lib/info-ajax.js 1.03 kB {0} [built] [73] ./~/sockjs-client/lib/iframe-bootstrap.js 2.9 kB {0} [built] [74] ./~/sockjs-client/lib/facade.js 723 bytes {0} [built] [75] (webpack)/hot/dev-server.js 1.85 kB {0} [built] [76] (webpack)/hot/log-apply-result.js 813 bytes {0} [built] [77] ./src/js/client.js 1.35 kB {0} [built] [78] ./~/react/react.js 56 bytes {0} [built] [79] ./~/react/lib/React.js 1.49 kB {0} [built] [80] ./~/react/lib/ReactDOM.js 3.71 kB {0} [built] [81] ./~/react/lib/ReactCurrentOwner.js 653 bytes {0} [built] [82] ./~/react/lib/ReactDOMTextComponent.js 4.32 kB {0} [built] [83] ./~/react/lib/DOMChildrenOperations.js 5 kB {0} [built] [84] ./~/react/lib/Danger.js 6.96 kB {0} [built] [85] ./~/fbjs/lib/ExecutionEnvironment.js 1.09 kB {0} [built] [86] ./~/fbjs/lib/createNodesFromMarkup.js 2.71 kB {0} [built] [87] ./~/fbjs/lib/createArrayFromMixed.js 2.36 kB {0} [built] [88] ./~/fbjs/lib/toArray.js 1.98 kB {0} [built] [89] ./~/fbjs/lib/invariant.js 1.51 kB {0} [built] [90] ./~/fbjs/lib/getMarkupWrap.js 3.06 kB {0} [built] [91] ./~/fbjs/lib/emptyFunction.js 1.09 kB {0} [built] [92] ./~/react/lib/ReactMultiChildUpdateTypes.js 861 bytes {0} [built] [93] ./~/fbjs/lib/keyMirror.js 1.27 kB {0} [built] [94] ./~/react/lib/ReactPerf.js 2.51 kB {0} [built] [95] ./~/react/lib/setInnerHTML.js 3.35 kB {0} [built] [96] ./~/react/lib/setTextContent.js 1.2 kB {0} [built] [97] ./~/react/lib/escapeTextContentForBrowser.js 849 bytes {0} [built] [98] ./~/react/lib/DOMPropertyOperations.js 7.88 kB {0} [built] [99] ./~/react/lib/DOMProperty.js 9.57 kB {0} [built] [100] ./~/react/lib/quoteAttributeValueForBrowser.js 746 bytes {0} [built] [101] ./~/fbjs/lib/warning.js 1.77 kB {0} [built] [102] ./~/react/lib/ReactComponentBrowserEnvironment.js 1.26 kB {0} [built] [103] ./~/react/lib/ReactDOMIDOperations.js 3.29 kB {0} [built] [104] ./~/react/lib/ReactMount.js 36.8 kB {0} [built] [105] ./~/react/lib/ReactBrowserEventEmitter.js 12.4 kB {0} [built] [106] ./~/react/lib/EventConstants.js 2.04 kB {0} [built] [107] ./~/react/lib/EventPluginHub.js 9.22 kB {0} [built] [108] ./~/react/lib/EventPluginRegistry.js 8.41 kB {0} [built] [109] ./~/react/lib/EventPluginUtils.js 6.79 kB {0} [built] [110] ./~/react/lib/ReactErrorUtils.js 2.27 kB {0} [built] [111] ./~/react/lib/accumulateInto.js 1.74 kB {0} [built] [112] ./~/react/lib/forEachAccumulated.js 893 bytes {0} [built] [113] ./~/react/lib/ReactEventEmitterMixin.js 1.3 kB {0} [built] [114] ./~/react/lib/ViewportMetrics.js 638 bytes {0} [built] [115] ./~/react/lib/Object.assign.js 1.26 kB {0} [built] [116] ./~/react/lib/isEventSupported.js 1.97 kB {0} [built] [117] ./~/react/lib/ReactDOMFeatureFlags.js 458 bytes {0} [built] [118] ./~/react/lib/ReactElement.js 8.07 kB {0} [built] [119] ./~/react/lib/canDefineProperty.js 629 bytes {0} [built] [120] ./~/react/lib/ReactEmptyComponentRegistry.js 1.38 kB {0} [built] [121] ./~/react/lib/ReactInstanceHandles.js 10.6 kB {0} [built] [122] ./~/react/lib/ReactRootIndex.js 723 bytes {0} [built] [123] ./~/react/lib/ReactInstanceMap.js 1.25 kB {0} [built] [124] ./~/react/lib/ReactMarkupChecksum.js 1.39 kB {0} [built] [125] ./~/react/lib/adler32.js 1.2 kB {0} [built] [126] ./~/react/lib/ReactReconciler.js 3.55 kB {0} [built] [127] ./~/react/lib/ReactRef.js 2.34 kB {0} [built] [128] ./~/react/lib/ReactOwner.js 3.45 kB {0} [built] [129] ./~/react/lib/ReactUpdateQueue.js 10.9 kB {0} [built] [130] ./~/react/lib/ReactUpdates.js 8.54 kB {0} [built] [131] ./~/react/lib/CallbackQueue.js 2.44 kB {0} [built] [132] ./~/react/lib/PooledClass.js 3.55 kB {0} [built] [133] ./~/react/lib/Transaction.js 9.55 kB {0} [built] [134] ./~/fbjs/lib/emptyObject.js 482 bytes {0} [built] [135] ./~/fbjs/lib/containsNode.js 1.43 kB {0} [built] [136] ./~/fbjs/lib/isTextNode.js 628 bytes {0} [built] [137] ./~/fbjs/lib/isNode.js 712 bytes {0} [built] [138] ./~/react/lib/instantiateReactComponent.js 4.52 kB {0} [built] [139] ./~/react/lib/ReactCompositeComponent.js 27.5 kB {0} [built] [140] ./~/react/lib/ReactComponentEnvironment.js 1.67 kB {0} [built] [141] ./~/react/lib/ReactPropTypeLocations.js 549 bytes {0} [built] [142] ./~/react/lib/ReactPropTypeLocationNames.js 611 bytes {0} [built] [143] ./~/react/lib/shouldUpdateReactComponent.js 1.49 kB {0} [built] [144] ./~/react/lib/ReactEmptyComponent.js 1.8 kB {0} [built] [145] ./~/react/lib/ReactNativeComponent.js 3.02 kB {0} [built] [146] ./~/react/lib/validateDOMNesting.js 13.1 kB {0} [built] [147] ./~/react/lib/ReactDefaultInjection.js 3.99 kB {0} [built] [148] ./~/react/lib/BeforeInputEventPlugin.js 14.9 kB {0} [built] [149] ./~/react/lib/EventPropagators.js 5.22 kB {0} [built] [150] ./~/react/lib/FallbackCompositionState.js 2.49 kB {0} [built] [151] ./~/react/lib/getTextContentAccessor.js 994 bytes {0} [built] [152] ./~/react/lib/SyntheticCompositionEvent.js 1.16 kB {0} [built] [153] ./~/react/lib/SyntheticEvent.js 5.79 kB {0} [built] [154] ./~/react/lib/SyntheticInputEvent.js 1.15 kB {0} [built] [155] ./~/fbjs/lib/keyOf.js 1.11 kB {0} [built] [156] ./~/react/lib/ChangeEventPlugin.js 11.5 kB {0} [built] [157] ./~/react/lib/getEventTarget.js 930 bytes {0} [built] [158] ./~/react/lib/isTextInputElement.js 1.03 kB {0} [built] [159] ./~/react/lib/ClientReactRootIndex.js 551 bytes {0} [built] [160] ./~/react/lib/DefaultEventPluginOrder.js 1.26 kB {0} [built] [161] ./~/react/lib/EnterLeaveEventPlugin.js 3.9 kB {0} [built] [162] ./~/react/lib/SyntheticMouseEvent.js 2.2 kB {0} [built] [163] ./~/react/lib/SyntheticUIEvent.js 1.64 kB {0} [built] [164] ./~/react/lib/getEventModifierState.js 1.3 kB {0} [built] [165] ./~/react/lib/HTMLDOMPropertyConfig.js 7.63 kB {0} [built] [166] ./~/react/lib/ReactBrowserComponentMixin.js 1.15 kB {0} [built] [167] ./~/react/lib/findDOMNode.js 2.17 kB {0} [built] [168] ./~/react/lib/ReactDefaultBatchingStrategy.js 1.92 kB {0} [built] [169] ./~/react/lib/ReactDOMComponent.js 36.9 kB {0} [built] [170] ./~/react/lib/AutoFocusUtils.js 816 bytes {0} [built] [171] ./~/fbjs/lib/focusNode.js 725 bytes {0} [built] [172] ./~/react/lib/CSSPropertyOperations.js 5.71 kB {0} [built] [173] ./~/react/lib/CSSProperty.js 3.5 kB {0} [built] [174] ./~/fbjs/lib/camelizeStyleName.js 1.03 kB {0} [built] [175] ./~/fbjs/lib/camelize.js 729 bytes {0} [built] [176] ./~/react/lib/dangerousStyleValue.js 1.93 kB {0} [built] [177] ./~/fbjs/lib/hyphenateStyleName.js 1 kB {0} [built] [178] ./~/fbjs/lib/hyphenate.js 822 bytes {0} [built] [179] ./~/fbjs/lib/memoizeStringOnly.js 778 bytes {0} [built] [180] ./~/react/lib/ReactDOMButton.js 1.15 kB {0} [built] [181] ./~/react/lib/ReactDOMInput.js 5.74 kB {0} [built] [182] ./~/react/lib/LinkedValueUtils.js 5.23 kB {0} [built] [183] ./~/react/lib/ReactPropTypes.js 12.5 kB {0} [built] [184] ./~/react/lib/getIteratorFn.js 1.17 kB {0} [built] [185] ./~/react/lib/ReactDOMOption.js 2.82 kB {0} [built] [186] ./~/react/lib/ReactChildren.js 5.83 kB {0} [built] [187] ./~/react/lib/traverseAllChildren.js 6.9 kB {0} [built] [188] ./~/react/lib/ReactDOMSelect.js 6.11 kB {0} [built] [189] ./~/react/lib/ReactDOMTextarea.js 4.35 kB {0} [built] [190] ./~/react/lib/ReactMultiChild.js 14.7 kB {0} [built] [191] ./~/react/lib/ReactChildReconciler.js 4.52 kB {0} [built] [192] ./~/react/lib/flattenChildren.js 1.65 kB {0} [built] [193] ./~/fbjs/lib/shallowEqual.js 1.28 kB {0} [built] [194] ./~/react/lib/ReactEventListener.js 7.51 kB {0} [built] [195] ./~/fbjs/lib/EventListener.js 2.65 kB {0} [built] [196] ./~/fbjs/lib/getUnboundedScrollPosition.js 1.09 kB {0} [built] [197] ./~/react/lib/ReactInjection.js 1.37 kB {0} [built] [198] ./~/react/lib/ReactClass.js 27.8 kB {0} [built] [199] ./~/react/lib/ReactComponent.js 5.04 kB {0} [built] [200] ./~/react/lib/ReactNoopUpdateQueue.js 3.94 kB {0} [built] [201] ./~/react/lib/ReactReconcileTransaction.js 4.58 kB {0} [built] [202] ./~/react/lib/ReactInputSelection.js 4.32 kB {0} [built] [203] ./~/react/lib/ReactDOMSelection.js 6.83 kB {0} [built] [204] ./~/react/lib/getNodeForCharacterOffset.js 1.66 kB {0} [built] [205] ./~/fbjs/lib/getActiveElement.js 924 bytes {0} [built] [206] ./~/react/lib/SelectEventPlugin.js 6.71 kB {0} [built] [207] ./~/react/lib/ServerReactRootIndex.js 868 bytes {0} [built] [208] ./~/react/lib/SimpleEventPlugin.js 17.4 kB {0} [built] [209] ./~/react/lib/SyntheticClipboardEvent.js 1.23 kB {0} [built] [210] ./~/react/lib/SyntheticFocusEvent.js 1.12 kB {0} [built] [211] ./~/react/lib/SyntheticKeyboardEvent.js 2.76 kB {0} [built] [212] ./~/react/lib/getEventCharCode.js 1.56 kB {0} [built] [213] ./~/react/lib/getEventKey.js 2.93 kB {0} [built] [214] ./~/react/lib/SyntheticDragEvent.js 1.13 kB {0} [built] [215] ./~/react/lib/SyntheticTouchEvent.js 1.33 kB {0} [built] [216] ./~/react/lib/SyntheticWheelEvent.js 1.99 kB {0} [built] [217] ./~/react/lib/SVGDOMPropertyConfig.js 3.8 kB {0} [built] [218] ./~/react/lib/ReactDefaultPerf.js 8.63 kB {0} [built] [219] ./~/react/lib/ReactDefaultPerfAnalysis.js 5.79 kB {0} [built] [220] ./~/fbjs/lib/performanceNow.js 844 bytes {0} [built] [221] ./~/fbjs/lib/performance.js 612 bytes {0} [built] [222] ./~/react/lib/ReactVersion.js 379 bytes {0} [built] [223] ./~/react/lib/renderSubtreeIntoContainer.js 463 bytes {0} [built] [224] ./~/react/lib/ReactDOMServer.js 766 bytes {0} [built] [225] ./~/react/lib/ReactServerRendering.js 3.3 kB {0} [built] [226] ./~/react/lib/ReactServerBatchingStrategy.js 673 bytes {0} [built] [227] ./~/react/lib/ReactServerRenderingTransaction.js 2.3 kB {0} [built] [228] ./~/react/lib/ReactIsomorphic.js 2.05 kB {0} [built] [229] ./~/react/lib/ReactDOMFactories.js 3.36 kB {0} [built] [230] ./~/react/lib/ReactElementValidator.js 10.8 kB {0} [built] [231] ./~/fbjs/lib/mapObject.js 1.47 kB {0} [built] [232] ./~/react/lib/onlyChild.js 1.21 kB {0} [built] [233] ./~/react/lib/deprecated.js 1.77 kB {0} [built] [234] ./~/react-dom/index.js 63 bytes {0} [built] [235] ./~/react-router/lib/index.js 2.38 kB {0} [built] [236] ./~/react-router/lib/Router.js 5.82 kB {0} [built] [237] ./~/warning/browser.js 1.81 kB {0} [built] [238] ./~/history/lib/createHashHistory.js 7.5 kB {0} [built] [239] ./~/invariant/browser.js 1.4 kB {0} [built] [240] ./~/history/lib/Actions.js 720 bytes {0} [built] [241] ./~/history/lib/ExecutionEnvironment.js 175 bytes {0} [built] [242] ./~/history/lib/DOMUtils.js 2.5 kB {0} [built] [243] ./~/history/lib/DOMStateStorage.js 2.01 kB {0} [built] [244] ./~/history/lib/createDOMHistory.js 1.29 kB {0} [built] [245] ./~/history/lib/createHistory.js 8.35 kB {0} [built] [246] ./~/deep-equal/index.js 3.05 kB {0} [built] [247] ./~/deep-equal/lib/keys.js 202 bytes {0} [built] [248] ./~/deep-equal/lib/is_arguments.js 641 bytes {0} [built] [249] ./~/history/lib/AsyncUtils.js 441 bytes {0} [built] [250] ./~/history/lib/createLocation.js 1.72 kB {0} [built] [251] ./~/history/lib/parsePath.js 1.16 kB {0} [built] [252] ./~/history/lib/extractPath.js 278 bytes {0} [built] [253] ./~/history/lib/runTransitionHook.js 775 bytes {0} [built] [254] ./~/history/lib/deprecate.js 299 bytes {0} [built] [255] ./~/react-router/lib/RouteUtils.js 3.49 kB {0} [built] [256] ./~/react-router/lib/RoutingContext.js 4.85 kB {0} [built] [257] ./~/react-router/lib/getRouteParams.js 578 bytes {0} [built] [258] ./~/react-router/lib/PatternUtils.js 6.79 kB {0} [built] [259] ./~/react-router/lib/useRoutes.js 10 kB {0} [built] [260] ./~/history/lib/useQueries.js 5.91 kB {0} [built] [261] ./~/history/~/query-string/index.js 1.48 kB {0} [built] [262] ./~/strict-uri-encode/index.js 182 bytes {0} [built] [263] ./~/react-router/lib/computeChangedRoutes.js 1.69 kB {0} [built] [264] ./~/react-router/lib/TransitionUtils.js 1.89 kB {0} [built] [265] ./~/react-router/lib/AsyncUtils.js 1.06 kB {0} [built] [266] ./~/react-router/lib/isActive.js 3.11 kB {0} [built] [267] ./~/react-router/lib/getComponents.js 971 bytes {0} [built] [268] ./~/react-router/lib/matchRoutes.js 6.1 kB {0} [built] [269] ./~/react-router/lib/PropTypes.js 1.32 kB {0} [built] [270] ./~/react-router/lib/Link.js 5.13 kB {0} [built] [271] ./~/react-router/lib/IndexLink.js 1.74 kB {0} [built] [272] ./~/react-router/lib/IndexRedirect.js 2.59 kB {0} [built] [273] ./~/react-router/lib/Redirect.js 3.5 kB {0} [built] [274] ./~/react-router/lib/IndexRoute.js 2.48 kB {0} [built] [275] ./~/react-router/lib/Route.js 2.46 kB {0} [built] [276] ./~/react-router/lib/History.js 404 bytes {0} [built] [277] ./~/react-router/lib/Lifecycle.js 2.4 kB {0} [built] [278] ./~/react-router/lib/RouteContext.js 807 bytes {0} [built] [279] ./~/react-router/lib/match.js 2.32 kB {0} [built] [280] ./~/history/lib/createMemoryHistory.js 4.34 kB {0} [built] [281] ./~/history/lib/useBasename.js 4.54 kB {0} [built] [282] ./src/js/pages/Archives.js 3.19 kB {0} [built] [283] ./src/js/components/Article.js 2.88 kB {0} [built] [284] ./src/js/pages/Featured.js 3.43 kB {0} [built] [285] ./src/js/pages/Layout.js 3.3 kB {0} [built] [286] ./src/js/components/layout/Footer.js 2.61 kB {0} [built] [287] ./src/js/components/layout/Nav.js 5.06 kB {0} [built] [288] ./src/js/pages/Settings.js 2.32 kB {0} [built] webpack: Compiled successfully.
期待的 UI 效果
Ref: https://github.com/learncodeacademy/react-js-tutorials/tree/master/2-react-router
一段 navigation 的代码
import { browserHistory, hashHistory, Router, Route, IndexRoute } from 'react-router'
import {Provider} from 'react-redux' render( <Provider store ={store}> <div> <Router history = { browserHistory }>
// 用 <Route> 来渲染 <Router> <Route path = '/' component= {App} > <IndexRoute component= {Layout} onEnter = {(nextState,replace)=>handleEnter(nextState,replace)}/> <Route path = '/login' component= {Login}/> <Route path = '/signup' component= {SignUp}/> </Route> </Router> </div> </Provider> , document.getElementById('app') )
component 改为了 element。
1) 'react-redux' 的 Provider
Ref: react-redux中的Provider组件 [有demo]
在 [React] 13 - Redux: react-redux 中有提到。
2) 'react-router' 的 browserHistory, hashHistory, Router, Route, IndexRoute
React Router4是一个流行的纯React重写的包。现在的版本中已不需要路由配置,现在一切皆组件。
所以,过去讲到的原始方式就没必要了:
- [React] 05 - Route: connect with ExpressJS
- [React] 06 - Route: koa makes your life easier
- 不使用 React Router的比对
RR4 本次采用单代码仓库模型架构(monorepo),这意味者这个仓库里面有若干相互独立的包,分别是:
-
react-router
# React Router 核心react-router-dom
# 用于 DOM 绑定 的 React Routerreact-router-native
# 用于 React Native 的 React Routerreact-router-redux
# React Router 和 Redux 的集成react-router-config
# 静态路由配置的小助手
关于路由的系统学习:
-
- Ref: React Router 4 简易入门
- Ref: React学习教程(7)React-Router简介&安装
- Ref: React Router 中文文档 [不错]
- 再 - 学 - 习 -
Ref: React.js 中文开发入门教学 - 使用路由组件 Router [v5.2.1]
基本的路由例子
手动修改URL,测试路由效果~
-
index.js
import { BrowserRouter } from 'react-router-dom' ReactDOM.render( <React.StrictMode> <BrowserRouter> <App /> </BrowserRouter> </React.StrictMode>, document.getElementById('root') );
HashRouter 是“弟弟” of BrowserRouter。
-
App.js
import Header from './components/Header'; import { Route } from 'react-router-dom'; import PageHome from './components/PageHome'; import PageAbout from './components/PageAbout'; import PageNews from './components/PageNews'; function App() { return ( <div> <Header></Header> <div className="p-4"> <Route path="/" exact> <PageHome></PageHome> </Route> <Route path="/news"> <PageNews></PageNews> </Route> <Route path="/about"> <PageAbout></PageAbout> </Route> </div> </div> ); } export default App;
导航栏组件 --> App.js --> PageNewsDetail.js
1. 那么导航栏,即可支持带有参数的NavLink。(导航栏是“发起点”)
<NavLink to="/news-detail/103" className="p-2">News3</NavLink>
2. Route path format 定义:有参数id,如下:
// App.js
<Route path="/news-detail/:id"> <PageNewsDetail></PageNewsDetail> </Route>
3. 通过route过来,提取其中的“参数”。
// /components/PageNewsDetail.js
import React from 'react'; import { useParams } from 'react-router-dom' const PageNewsDetail = () => { const params = useParams(); console.log(params) return ( <div> <h1>PageNewsDetail</h1> <h2>id: {params.id}</h2> <hr /> <pre> {JSON.stringify(params, null, 4)} </pre> </div> ) } export default PageNewsDetail;
导航栏
点击后,自动跳转到制定的URL。所以,头部组件添加导航link ~
import React from 'react'; import './Header.css'; import { NavLink } from 'react-router-dom' const Header = () => { return ( <div className="navbar bg-header p-2 shadow d-flex justify-content-between"> <div className="text-light"> <i className="bi bi-life-preserver"></i> <span className="fs-5 ps-2">React.js</span> </div> <div> <NavLink to="/" className="text-decoration-none px-1 text-secondary" activeClassName="text-light" exact>Home</NavLink> <NavLink to="/news" className="text-decoration-none px-1 text-secondary" activeClassName="text-light">News</NavLink> <NavLink to="/about" className="text-decoration-none px-1 text-secondary" activeClassName="text-light">About</NavLink> </div> </div> ) } export default Header;
Nav 的导航栏 会有“高亮” 效果。
如果要实现”自定义类名”,className里面需要写成 ”函数“。把函数单独定义出来,这里只是调用,会更优雅一些。
Nested Routes
这个例子有点水。看样子,只是“子组件”中,而非“父组件”中,定义了Route罢了~
import React from 'react'; import { Route, NavLink } from 'react-router-dom' const PageAbout = () => { return ( <div> <h1>PageAbout</h1> <NavLink to="/about/komavideo" exact>详细页面</NavLink> // 已经在当前的url下的页面~,点击后跳转。 <hr /> <Route path="/about/komavideo"> // 跳转到这个url下的页面。 <h2 className="text-success">小马技术视频</h2> </Route> </div> ) } export default PageAbout;
以下是嵌套路由的UI展示。
-
-
创建 News.jsx and Message.jsx, 然后再重构下 路由表 以及 Home.jsx
-
Message.jsx 中添加如上图一般的 “超链接”。
News.jsx 只是简单的添加如下。<li> 表示:用于表示列表里的条目
-
-
然后,1) 增加 children 于路由表
-
./routes/index.js
import Home from '../pages/Home'
import Message from '../pages/Message'
import News from '../pages/News'
export default [ { path: '/about', element:<About/> }, { path: '/home', element:<Home/>, children: [ { path: 'news', element: <News/> }, { path: 'message', element: <Message/> } ] }, { path: '/', element: <Navigate to="/about"/> } ]
-
-
然后,2) refactor Home.jsx
-
NavLink指向的组件的内容会显示在 <Outlet />部分。
在上图 linn4-5之间可以加上如下。该方法,用来呈现当前组件中所渲染的嵌套路由。
console.log('###', useOutline())
路由的 param 参数 by useParams()
针对提取参数,引入:最新版本的路由param参数,这里直接是个三级目录的嵌套路由的例子。
'children' 嵌套如下。
routes/index.js
{ path: '/home', element:<Home/>, children: [ { path: 'news', element: <News/> }, { path: 'message', element: <Message/>
children:[
{
path:'detail/:id/:title/:content', # 因为detail是内容丰富的,所以这里的url自然会丰富许多
element:<Detail/>
}
] } ] },
Message.jsx 中 大换血。需要增加detail.js文件。
url: /home/message/detail
此时点击 "消息1“,下面会显示组件的内容,但注意:url 却不变。
下一步,我们希望 给下面 “传参” by url。
./Message.jsx
return { <div> <ul> { message.map( (m)=>{ return ( // 路由链接 <li key={m.id}> <Link to={`detail/$(m.id)/$(m.title)/$(m.content)`}>{m.title}</Link> # 点击这个 title,跳转到这个链接,该链接对应的组件在上面route定义,遂展示detail内容。 </li> ) }) } </ul> <hr /> {/* 指定路由组件的展示位置 */} <Outlet /> </div> ) }
以下是 detail.jsx组件 的实现 by useParams()。
过去“类组件”时的:history, match, location之类,现在变成怎样了呢 in 函数组件? 如上,useMatch能用(line6),但没有必要。line5的形式就挺好!
search 参数 (另一种形式的url 参数定义)
(1)更新 routes/index.jsx,如下不再需要detail后面的东西。(如 state 参数的)
(2)主要url中参数格式的变化。
./Message.jsx return { <div> <ul> { message.map( (m)=>{ return ( // 路由链接 <li key={m.id}> <Link to=`detail?id=${m.id}&title=${m.title}&content=${m.content}`}>{m.title}</Link> </li> ) }) } </ul> <hr /> {/* 指定路由组件的展示位置 */} <Outlet /> </div> ) }
(3)Detail.jsx如下,通过 useSearchParams() 获得url中的各个参数。如下示范,通过点击一个按钮,改变url(其中自带参数),重新render后,自然就改变了Detail组件的内容。
state 参数
(1)更新 routes/index.jsx,如下不再需要detail后面的东西。
path:'detail/:id/:title/:content', # 因为detail是内容丰富的,所以这里的url自然会丰富许多
path:'detail',
(2)更新 Message.jsx,给组件传参采用新的format,请见 link to。
./Message.jsx return { <div> <ul> { message.map( (m)=>{ return ( // 路由链接 <li key={m.id}> <Link
to="detail"
state={{
id:m.id,
title:m.title,
content:m.content,
}}
>{m.title}</Link> </li> ) }) } </ul> <hr /> {/* 指定路由组件的展示位置 */} <Outlet /> </div> ) }
(3)Detail.jsx如 下,通过 useLocation() 获得state中的各个参数。
useResolvedPath()
给定一个 URL值,解析其中的:path, search, hash值。
useResolvedPath('/user?id=001&name=tom#qwe)
路由重定向
无效路径,自然需要redirect to an available web page (URL).
import { Route, Switch, Redirect } from 'react-router-dom'; ... // <Route path="/" exact> // <PageHome></PageHome> // </Route> ... <Route path="/" exact> <Redirect to="/home"></Redirect> </Route> <Route path="/home"> <PageHome></PageHome> </Route> ...
-
-
404 处理
-
找不到,则导入默认的一个 "404组件"。
import NotFound from './pages/NotFound'; ... <Switch> ... <Route path="*"> <NotFound></NotFound> </Route> </Switch> ...
"404组件" 定义如下。
import React from 'react'; const NotFound = () => { return ( <h1>404:NotFound</h1> ) } export default NotFound;
switch 改为 routes 即可。
Navigate 只要 ”被渲染“,就会“跳转“。
例如,鼠标划过某个带有链接能力的图片,但其实不应该触发这个链接,所以navigate在这里就不合适。
如果加上 replace, 重定向后的页面 就无法通过”浏览器回退“ 返回,因为被替换掉了~
<Navigate to="/about" replace={true}/>
路由表 - useRoutes
越来越像vue,以及django传统的路由定义方式。
import routes from "./routes"
const element = useRoutes(routes)
以下是上面的 蓝色的 const element。
<div className="panel-body"> {element} </div>
编程路由 - useHistory
这里的例子,通过onClick来体现“编程的方式”。
import React from 'react'; const Login = () => { return ( <h1>Login</h1> ) } export default Login;
import React from 'react'; import './Header.css'; import { NavLink, useHistory } from 'react-router-dom' const Header = (props) => {
// 新增代码 const history = useHistory(); const btn_login_click = () => { history.push("/login") } const btn_logout_click = () => { history.push("/") }
return ( <div className="navbar bg-header p-2 shadow d-flex justify-content-between"> <div className="text-light"> <i className="bi bi-life-preserver"></i> {/*新增代码*/} <NavLink className="fs-5 ps-2 link-light text-decoration-none" to="/">React.js</NavLink> </div> <div> {/*新增代码*/} <button className="btn btn-primary btn-sm mx-1" onClick={btn_login_click}>登陆</button> // --> 通过onClick函数中的push达到了 NavLink中to的效果 <button className="btn btn-danger btn-sm mx-1" onClick={btn_logout_click}>退出</button> </div> </div> ) } export default Header;
Ref: 编程式路由导航
通过点击按钮达到跳转的效果,有点类似上面的push 例子。但这里的v6又出现了什么新意了么?
若在 ./index.js 下将某个组件 放置在 </BrowserRouter> 外,就可以不受路由体系的范围控制。
./pages/Message.jsx
import React, {useState} from 'react'; import { Link, Outlet, useNavigate, useInRouterContext } from 'react-router-dom' export default function Message() { const navigate = useNavigate()
console.log("***", useInRouterContext()) # <---判断是否在路由体系下的控制范围之内 True or False
const [message] = useState([
...
])
// 点击按钮后,触发该函数中,通过 navigate 进入相对的url path. function showDetail_onClick(m) { navigate('detail', {
replace: false,
state: {
id:m.id,
title:m.title,
content:m.content
}
})
} }
如下 ./components/header/index.jsx,简单的 -1, 1就可以实现前后历史浏览进退,貌似更为简单。
useNavigationType()
返回当前的导航类型(用户是如何来到当前页面的)
POP, PUSH, REPLACE
const result = useOutlet()
console.log(result)
页面跳转传参 - useLocation
那上个页面跳转过来时,顺便传过来几个参数。
const btn_login_click = () => { // 传入登陆页面2个参数:name, password history.push("/login?name=koma&password=12345678") }
import React from 'react'; import { useLocation } from 'react-router-dom' const Login = () => { const location = useLocation(); const urlParams = new URLSearchParams(location.search); console.log(urlParams.toString()); return ( <React.Fragment> <h1>Login</h1> <hr /> <div className="fs-2"> Name: <span className="badge bg-primary">{urlParams.get("name")}</span> </div> <div className="fs-2"> Password: <span className="badge bg-secondary">{urlParams.get("password")}</span> </div> </React.Fragment> ) } export default Login;
ReactRouter v6 (draft)
Ref: 2022针对 ReactRouter6 加更章节:p127-141 [v6]
Ref: 总结变化
函数组件将成为未来趋势!
react-router
react-router-dom
react-router-native
移除了 <Switch/> 新增 <Routes/>
component = {About} 变为 element = {About}
新增多个 hook: useParams, useNavigate, useMatch等。(类组件中不能使用Hook的,所以官方u推荐“函数组件”)