react外围概念及其利用
第1章:React入门
1.1 React根底意识
1.1.1 官网材料
React是什么?React是一个申明式,高效且灵便的用于构建用户界面的 JavaScript 库(只关注于View层)。应用 React 能够将一些简短、独立的代码片段组合成简单的 UI 界面,这些代码片段被称作“组件”。
1.1.2 React的特点
- Declarative 申明式: 以申明式编写UI,让代码更加牢靠且不便调试
- Component-Based 组件化: 创立领有各自状态的组件,再由组件组成更加简单的UI
- Learn Once, Write Anywhere 一次学习,随处编写:无论什么技术栈,无需重写现有代码,引入React即可开发新性能,同时还能够进行服务器端渲染
- 高效: (1)虚构DOM,不间接操作DOM (2)DOM Diff算法,最小化页面重绘
- 单向数据流: 父子组件采纳props传递数据
1.2 React根本应用
如何将 React 组件增加到现有的 HTML 页面中。你能够基于本人现有的网站,或创立一个空的 HTML 文件来练习。
1.2.1 步骤 1:增加一个 DOM 容器到 HTML
首先,关上你想要编辑的 HTML 页面。增加一个空的 <div>
标签作为标记你想要用 React 显示内容的地位。例如:
<!-- ... 其它 HTML ... --><div id="like_button_container"></div><!-- ... 其它 HTML ... -->
咱们给这个 <div>
加上惟一的 id
HTML 属性。这将容许咱们稍后用 JavaScript 代码找到它,并在其中显示一个 React 组件。React 会替换 DOM 容器内的任何已有内容。
1.2.2 步骤 2:增加 Script 标签
接下来,在 </body>
完结标签之前,向 HTML 页面中增加3个 <script>
标签, 前两个标签加载 React。第三个将加载组件代码:
<!-- ... 其它 HTML ... --><!-- 加载 React。--><!-- 留神: 部署时,将 "development.js" 替换为 "production.min.js"。--><script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script><script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script><!-- 加载咱们的 React 组件。--><script src="like_button.js"></script>
1.2.3 步骤 3:创立一个 React 组件
在 HTML 页面文件的同级目录下创立一个名为 like_button.js
的文件。在 like_button.js
的底部,退出以下两行代码。
const e = React.createElementconst domContainer = document.querySelector('#like_button_container');ReactDOM.render(e('button', { onClick: () => this.setState({ liked: true }) }, 'Like'), domContainer);
这两行代码会找到咱们在步骤 1 中增加到 HTML 里的 <div>
,而后在它外部显示咱们的 React 组件 “Like” 按钮。
1.2.4 步骤 4:应用 React 和 JSX
在下面的示例中,咱们只依赖了浏览器原生反对的个性。这就是为什么咱们应用了 JavaScript 函数调用来通知 React 要显示什么, 然而,React 还提供了一种用 JSX 来代替实现的抉择:
// 显示一个 "Like" <button>return ( <button onClick={() => this.setState({ liked: true })}> Like </button>);
在我的项目中尝试 JSX 须要应用到babel
, JSX代码所在的<script>
标签须要增加type="text/babel"
属性:
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
然而这种引入形式不能应用在生产环境中。本节只是一个简略的原生示例,理论中我的项目咱们都是举荐应用集成的工具链来实现最佳的用户和开发人员体验。
1.3 React JSX 以及虚构DOM
1.3.1 虚构DOM概念
- React提供了一些API来创立“特地”的js对象,如上文利用的React.createElement办法
- 虚构DOM对象最终都会被React转换为实在的DOM并渲染。咱们在写代码时关注点都在虚构DOM的相干数据上
将一个元素渲染为DOM时,须要一段html申明根节点,而后传入只需把它们一起传入 ReactDOM.render()
// HTML片段,DOM根节点<div id="root"></div>// JS片段const element = <h1>Hello, world</h1>;ReactDOM.render(element, document.getElementById('root'));
render
办法的两个参数:纯js或jsx创立的虚构DOM对象,以及用来蕴含虚构DON元素的根节点对象
1.3.2 JSX相干概念
JSX——JavaScript XML,是React定义的一种相似于XML的拓展语法,其作用是用来创立React虚构DOM对象JSX 能够很好地形容 UI 应该呈现出它应有交互的实质模式。JSX 可能会使人联想到模版语言,但它具备 JavaScript 的全副性能。React 并没有采纳将标记与逻辑进行拆散到不同文件这种人为地拆散形式,而是通过将二者独特寄存在称之为“组件”的涣散耦合单元之中,来实现关注点拆散。
const element = <h1>Hello, world!</h1>;
语法规定:
- 遇到< 结尾的代码,以标签语法解析,html同名标签转换为html同名元素,其余标签须要特地解析,往往是组件
- 遇到以{结尾的代码,以JS语法解析。
- 因为 JSX 会编译为 React.createElement 调用模式,所以 React 库也必须蕴含在 JSX 代码作用域内。即便没有显式地调用React及其组件,仍然须要引入它
- 用户自定义的组件必须的大写字母结尾
一个JSX语法片段只能返回一个根元素,所以必须有外层元素包裹。如果须要返回多个元素,Fragments 容许你将子列表分组,而无需向 DOM 增加额定节点。短语法是
<></>
<React.Fragment> <td>Hello</td> <td>World</td>
布尔类型、Null 以及 Undefined 将会疏忽, 以下元素渲染后果雷同
<div /><div></div><div>{false}</div><div>{null}</div><div>{undefined}</div><div>{true}</div>
这有助于在特定条件下渲染元素
<div> {showHeader && <Header />} <Content /></div>
JSX自身也是表达式,在编译之后,JSX 表达式会被转为一般 JavaScript 函数调用,并且对其取值后失去 JavaScript 对象。能够:
- 在 if 语句和 for 循环的代码块中应用 JSX
- 将 JSX 赋值给变量
- 把 JSX 当作参数传入
从函数中返回 JSX
JSX中能够通过应用引号,来将属性值指定为字符串字面量:
const element = <div tabIndex="0"></div>;
因为 JSX 语法上更靠近 JavaScript 而不是 HTML,所以 React DOM 应用
camelCase
(小驼峰命名)来定义属性的名称,而不应用 HTML 属性名称的命名约定。1.4 模块与组件和模块化与组件化的了解
1.4.1 模块
- 了解:向外提供特定JS性能的程序,个别是一个JS文件
- 为什么须要模块:现代化前端工程,尤其是大型工程,JS代码更多更简单,须要更好的机制去优化开发环节的便当以及生产环节的加载性能
作用:进步JS的复用能力,进步编程效率,进步运行效率
1.4.2 组件
- 了解: 组件是用来实现特定性能成果的代码汇合,包含构造、款式与行为(HTML/CSS/JS)
- 为什么须要组件:古代前端工程中一个界面的性能更加简单,须要进行拆分并关注以后最小单元
- 作用:进步JS的复用能力,进步编程效率,进步运行效率
React的组件分为:(1)继承React的class类组件(2)函数组件
第2章:React面向组件编程
2.1 根本了解和应用
2.1.1 自定义组件
// 形式一:工厂函数组件const MyFactoryComp = (props) => {return <h1>函数组件</h1>}// 形式二:ES6类组件class MyClassComp extends React.Component {render () { return <h1>类组件</h1>}}
// 渲染组件ReactDom.render(<MyFactoryComp />, document.getElementById('root'))
2.1.2 注意事项
- 组件名首字母必须大写,没有大写的在援用之前都须要先赋予首字母大写的别名,而后再援用别名
- 虚构DOM元素只能有一个根元素,如果不不便插入根元素可应用
<></>
虚构DOM元素必须有完结标签
2.1.3 渲染过程
- React创立外部虚构DOM对象
- 将其解析为实在的DOM片段
插入到指定元素中,并替换元素下所有内容,所以
#root
元素节点的内容写了也是有效的2.2 组件三大属性之state
2.2.1 定义及定义方法
函数组件没有
state
,类组件才能够保护state
,然而函数组件也有本人的hook来进行外部数据管理。类组件中有两种形式申明state
并进行初始赋值:在
class
构造函数constructor
中进行初始赋值class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); }}
间接定义
state
对象变量class Clock extends React.Component { state = {date: new Date()} render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); }}
2.2.2 示例
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; } componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); } componentWillUnmount() { clearInterval(this.timerID); } tick() { this.setState({ date: new Date() }); } render() { return ( <div> <h1>Hello, world!</h1> <h2>It is {this.state.date.toLocaleTimeString()}.</h2> </div> ); }}ReactDOM.render( <Clock />, document.getElementById('root'));
如何了解上述代码的调用程序
- 当 <Clock /> 被传给
ReactDOM.render()
的时候,React 会调用 Clock 组件的构造函数。此时第一次更新state
- 之后 React 会调用组件的
render()
办法。组件第一次被渲染 - 当 Clock 的输入被插入到 DOM 中后,React 就会调用
ComponentDidMount()
生命周期办法。设置tick()
办法 - 每秒都会调用一次
tick()
办法。更新setState()
,从新调用render()
办法 组件被移除时,调用
componentWillUnmount()
生命周期办法,计时器被移除2.2.3 注意事项
- 当 <Clock /> 被传给
- 不要间接批改state,须要应用
setState()
,这个函数能够接管一个对象,也能够接管一个函数,构造函数和申明处是惟一能够间接给state
赋值的中央 state
的更新可能是异步的,不能依赖他们的值来更新下一个状态,或者在代码后立刻应用新值做一些事件// Correctthis.setState((state, props) => ({ counter: state.counter + props.increment}));
state
的更新会被合并,当你调用setState()
的时候,React 会把你提供的对象合并到以后的 state2.3 组件三大属性之props
2.3.1 定义及定义方法
组件的概念相似于JS函数,该函数能够了解为:入参——即组件标签上的所有属性(attributes)以及子组件(children)转换为单个对象传递给组件,即props,返回值:返回React元素
在函数组件中,props是写明的惟一参数,在类组件中,props能够在组件外部间接援用2.3.2 示例
// 函数组件举例function Welcome(props) {return <h1>Hello, {props.name}</h1>;}// 类组件举例class Welcome extends React.Component {render() { return <h1>Hello, {this.props.name}</h1>;}}// 组件调用const element = <Welcome name="Sara" />;ReactDOM.render(element,document.getElementById('root'));
上例中,
name="Sara"
属性被赋予了组件,就会被转换为{name: 'Sara'}
作为props
传递给组件2.3.3 注意事项
props是只读的,无论是函数组件还是类组件,都不能扭转本身的props,所有组件必须像保护纯函数一样保障props不被批改。
2.4 组件三大属性之refs
2.4.1 定义及定义方法
在某些状况下,你须要在典型数据流之外强制批改子组件。如获取已渲染元素在屏幕上宽高、手动给input聚焦等,React提供了refs来获取实在的DOM。
refs须要像state一样进行初始赋值2.4.2 示例
Refs 是应用
React.createRef()
创立的,并通过ref
属性附加到 React 元素。在结构组件时,通常将 Refs 调配给实例属性,以便能够在整个组件中援用它们。class MyComponent extends React.Component {constructor(props) { super(props); this.myRef = React.createRef(); // 将 Refs 调配给实例属性, 创立一个 ref 来存储 myRef 的 DOM 元素}componentDidMounted () { // 对该节点的援用能够在 ref 的 current 属性中被拜访 const node = this.myRef.current; ...}render() { return <div ref={this.myRef} />;}}
2.4.3 注意事项
- 如果一件事件能够通过申明式来实现,那最好不要应用
refs
refs
只能在类组件中应用,不能在函数组件中应用,因为它没有实例ref
会在componentDidMount
或componentDidUpdate
生命周期钩子触发前更新。挂载前,给current
属性传入DOM元素,卸载前,传入null
元素2.5 事件处理
2.5.1 示例
class Toggle extends React.Component {constructor(props) { super(props); this.state = {isToggleOn: true}; // 为了在回调中应用 `this`,这个绑定是必不可少的 this.handleClick = this.handleClick.bind(this);}handleClick() { this.setState(state => ({ isToggleOn: !state.isToggleOn }));}render() { return ( <button onClick={this.handleClick}> {this.state.isToggleOn ? 'ON' : 'OFF'} </button> );}}ReactDOM.render(<Toggle />,document.getElementById('root'));
2.5.2 注意事项
通过
onXxx
(留神驼峰式)属性指定组件的事件处理函数(函数而非字符串)// 原生事件<button onclick="activateLasers()"> Activate Lasers</button>// React事件<button onClick={activateLasers}> Activate Lasers</button>
不能通过返回
false
的形式阻止默认行为。你必须显式的应用preventDefault
。function ActionLink() { function handleClick(e) { e.preventDefault(); console.log('The link was clicked.'); } return ( <a href="#" onClick={handleClick}> Click me </a> );}
- 参数
e
是一个合成事件,并且作为默认第一个参数传递,能够在回调函数内间接调用 须要审慎看待事件回调函数中的
this
,class
的办法默认不会绑定this
,如果函数外部须要调用类组件的this
, 须要显式绑定或者采纳箭头函数申明回调函数2.6 组件生命周期
2.6.1 生命周期定义
生命周期是组件对象从创立到销毁所经验的特定的生命周期阶段。React组件对象定义了一系列的钩子函数,能够在生命周期的特定时刻执行这些函数。咱们在定义组件中能够重写生命周期钩子函数,达到咱们本人的目标。
2.6.2 生命周期流程
进行细分能够分为:阶段 调用办法 挂载阶段 constructor()
/static getDerivedStateFromProps()
/render()
/componentDidMount()
更新阶段 static getDerivedStateFromProps()
/shouldComponentUpdate()
/render()
/getSnapshotBeforeUpdate()
/componentDidUpdate()
卸载 componentWillUnmount()
错误处理 static getDerivedStateFromError()
/componentDidCatch()
2.6.3 注意事项
render()
办法是class
组件中惟一必须实现的办法- 在
constructor()
函数中不要调用setState()
办法, 要防止在构造函数中引入任何副作用或订阅 - 防止将 props 的值复制给 state
componentWillUnmount()
中须要卸载具备副作用的一些办法,比方定时器、勾销网络申请、革除挂载时的订阅等2.7 HOOK
ES6 class
组件能够在外部定义state
进行数据管理,函数组件当初也有了相似性能的Hook
,能够在不编写class
的状况下应用state
以及其余的React个性。以前咱们说,简单组件用类组件,函数组件只适宜简略组件,有了Hooks
撑持之后,函数组件也能够向类组件一样实现更加简单的性能。
Hook 是一些能够让你在函数组件里“钩入” Reactstate
及生命周期等个性的函数。其中最罕用的就是State Hook
和Effect Hook
,前者提供了useState
办法向组件外部增加一些state
,后者则提供了useEffect办法来模仿componentDidMount
、componentDidUpdate
和componentWillUnmount
生命周期。2.7.1 State Hook
示例
// 类组件写法class Example extends React.Component {constructor(props) { super(props); this.state = { count: 0 };}render () { return ( <> <button onClick={() => this.setState({ count: this.state.count + 1 })}> Click me </button> <p>You clicked {this.state.count} times</p> </> )}}// 函数组件写法import React, { useState } from 'react';function Example() {// 申明一个叫 “count” 的 state 变量const [count, setCount] = useState(0);const [fruit, setFruit] = useState('banana');return <> <button onClick={() => setCount(count + 1)}> Click me </button> <p>You clicked {count} times</p></>)
- 引入React中的
useState
- 通过调用
useState
申明一个state
变量,该函数返回一对值,通过方括号进行数组解构赋值,咱们定义两个命名变量,第一个解构变量是state
变量名,第二个解构变量是对该state
变量进行更新的函数 - 同类组件中的
state
变量一样,咱们不能间接批改它,须要应用上述第二个解构变量进行间接批改它(如同类组件中的setState
一样) - 函数组件内没有
this
,咱们在援用变量的时候,间接应用上述第一个命名解构变量即可,无需应用this.Xxx
多个
state
变量能够进行屡次进行申明和调用,与类组件中不同的是,对不同的state
变量进行更新时,不再是合并,而是间接替换指标变量2.7.2 Effect Hook
示例
import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState(0);// Similar to componentDidMount and componentDidUpdate:useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${count} times`;});return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div>);}
useEffect Hook
有两个参数,第一个参数是一个带有副作用的函数,在DOM更新之后会调用它,即componentDidMount
、componentDidUpdate
生命周期钩子之后。第二个参数是外部useState
和函数组件参数——即props
中若干变量组成的数组,如果省略第二个参数,则意味着每次更新渲染之后都会执行这个useEffect Hook
。如果咱们的useEffect Hook
只依赖于局部变量的批改,能够在数组中订阅它。如果只想在挂载和卸载时执行,传入空数组[]
就好了。有些
useEffect Hook
是须要被手动革除的。当订阅内部数据源,革除工作十分重要,能够避免引起内存泄露。WHY???当然是闭包。useEffect Hook
返回一个函数,React 将会在执行革除操作时调用它,相当于componentWillUnmount
生命周期调用。import React, { useState, useEffect } from 'react';function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); // Specify how to clean up after this effect: return function cleanup() { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline';}
2.7.3 其余罕用Hook
useCallback
返回一个memoized
回调函数。const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b],);
把内联回调函数及依赖项数组作为参数传入
useCallback
,它将返回该回调函数的memoized
版本,该回调函数仅在某个依赖项扭转时才会更新。当你把回调函数传递给通过优化的并应用援用相等性去防止非必要渲染(例如shouldComponentUpdate
)的子组件时,它将十分有用。useMemo
返回一个memoized
值。const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
把“创立”函数和依赖项数组作为参数传入
useMemo
,它仅会在某个依赖项扭转时才从新计算memoized
值。这种优化有助于防止在每次渲染时都进行高开销的计算。useReducer
useRef
useImperativeHandle
useLayoutEffect
useDebugValue
自定义Hook
2.7.4 注意事项
- 只在最顶层应用Hook, 不要在循环、条件或嵌套函数中调用Hook
只在React函数中调用Hook,不要在一般的JavaScript函数只能怪调用Hook,能够在React的函数组件中调用或在自定义Hook中调用
第3章:React利用(基于React脚手架)
3.1 应用脚手架工具创立React利用
3.1.1 脚手架介绍
React官网举荐应用
Create React App
创立一个新的单页利用。如果是大型简单的前端我的项目,咱们也能够本人从0开始搭建——脚手架工具蕴含三大组件:package管理器、打包器、编译器,所以咱们能够用npm + webpack + babel组件本人的工具。
脚手架工具能够给咱们带来的便当包含:- 拓展我的项目和组件的规模,以工程化的思维治理我的项目,模块化、组件化、工程化
- 蕴含了我的项目所需的根本配置
- 指定好了根底依赖
- 提供了一个最简略demo能够间接查看成果
清晰的文件治理目录
3.1.2 创立我的项目并启动
Create React App
会配置你的开发环境,以便使你可能应用最新的JavaScript
个性,提供良好的开发体验,并为生产环境优化你的应用程序。npx create-react-app my-appcd my-appnpm start
3.1.3 了解我的项目构造
3.2 demo
第4章:开发中若干要点
4.1 组件间通信
4.1.1 形式一:通过props传递
- 独特的数据放在父组件上,特有的数据放在外部作为
state
保护 通过
props
能够传递个别数据和函数,一层一层传递个别数据是由父组件传递给子组件,子组件进行数据读取,而函数常常被用来在子组件中调用并传递数据给父组件。
4.1.2 形式二:应用音讯公布订阅机制
能够借助PubSub库来实现
4.1.3 形式三: Context
Props
属性是自上而下传递的,但当一个属性是应用程序中许多组件都须要的时候,显式地通过组件树层层传递就显得繁琐,Context
提供了一个无需为每层组件手动增加props
,就能在组件树间进行数据传递的办法。Context
设计目标是为了共享那些对于一个组件树而言是“全局”的数据,例如以后认证的用户、主题或首选语言。props
代码示例:class App extends React.Component {render() { return <Toolbar theme="dark" />;}}function Toolbar(props) {// Toolbar 组件承受一个额定的“theme”属性,而后传递给 ThemedButton 组件。// 如果利用中每一个独自的按钮都须要晓得 theme 的值,这会是件很麻烦的事,// 因为必须将这个值层层传递所有组件。return ( <div> <ThemedButton theme={props.theme} /> </div>);}class ThemedButton extends React.Component {render() { return <Button theme={this.props.theme} />;}}
Context
代码示例// 应用Context// Context 能够让咱们毋庸明确地传遍每一个组件,就能将值深刻传递进组件树。// 为以后的 theme 创立一个 context(“light”为默认值)。const ThemeContext = React.createContext('light');class App extends React.Component {render() { // 应用一个 Provider 来将以后的 theme 传递给以下的组件树。 // 无论多深,任何组件都能读取这个值。 // 在这个例子中,咱们将 “dark” 作为以后的值传递上来。 return ( <ThemeContext.Provider value="dark"> <Toolbar /> </ThemeContext.Provider> );}}// 两头的组件再也不用指明往下传递 theme 了。function Toolbar() {return ( <div> <ThemedButton /> </div>);}class ThemedButton extends React.Component {// 指定 contextType 读取以后的 theme context。// React 会往上找到最近的 theme Provider,而后应用它的值。// 在这个例子中,以后的 theme 值为 “dark”。static contextType = ThemeContext;render() { return <Button theme={this.context} />;}}
注意事项:
Context
次要利用场景在于很多不同层级的组件须要拜访同样一些的数据。请审慎应用,因为这会使得组件的复用性变差。4.1.4 形式四:Redux
Redux提供一种全局的应用程序状态管理工具,能够像
vue
中的vuex
一样不便地治理共享状态。前面会具体介绍。4.2 异步申请
React自身只关注于界面,并不蕴含
ajax
申请,当须要前后台交互时,须要集成第三方ajax
库。axios
和fetch
是较为罕用的ajax
申请库:axios
: 封装了XmlHttpRequest
对象的ajax
的轻量级工具,反对promise
,浏览器端和服务端均可应用fetch
: 是新版浏览器反对的原生函数,老版本浏览器并不反对,须要反对老版本的话可增加fetch.js
,不再应用XmlHttpRequest
对象提交ajax
4.3 ES6及TypeScript
ES6: 因为React类组件是采纳
ES6 class
定义的,所以咱们须要在一开始就配合babel
应用。
当我的项目越来越大时,减少动态类型查看器能够在运行前辨认某些类型谬误。React中提供了PropTypes
来限定props
的输出类型,但其实在函数输入输出、state
治理、接口对立标准等各处都须要进行动态类型查看。
倡议在大型代码库中应用Flow
或TypeScript
来代替,尤其是TypeScript
。4.4 开源UI组件库
- material-ui 国外的一款开源react UI组件库
ant-design 由国内蚂蚁金服打造的react UI组件库, 次要用于研发企业级中后盾产品,同时提供挪动端版本 ant-design-mobile
留神:在应用UI组件库时,尽量采纳按需加载的形式打包组件,不要讲UI组件库一次性全盘导入,不利于放大打包体积。
第5章:react-router
5.1 基本概念
5.1.1 react-router 与 react-router-dom
react-router
是react的一个专门用于实现SPA利用的插件库,基于react的我的项目基本上都会用到此库,它实现了路由的外围性能。目前咱们应用的是react-router5
的版本。react-router-dom
则是基于react-router
并退出了在浏览器运行环境下的一些性能,例如Link
组件、BrowserRouter
和HashRouter
组件。5.1.2 路由分类
路由是一种映射关系,
key
为路由门路,value
为function/component
- 后盾路由 服务器路由,
value
是function
,用于解决用户提交的申请并返回响应数据 前台路由 浏览器端路由,
value
是component
,当申请路由path匹配时,界面会更新显示对应的路由,没有产生http申请5.1.3 路由组件分类
- 根组件:
BrowserRouter
(history模式) 和HashRouter
(hash模式)BrowserRouter
(history模式) 和HashRouter
(hash模式)作为路由配置的最外层容器,是两种不同的模式,可依据须要抉择。 - 门路匹配组件:
Route
和Switch
导航组件:
Link
和NavLink
5.2 history 库
history
库是react-router
包的唯二依赖,另一个是react自身。这个库治理浏览器会话历史工具库,有三种模式:browser history
, 基于H5 History
Api 封装hash history
基于window.location.hash
封装memory history
在no-DOM环境中实用,比方RN
history
对象提供了和H5 History
Api十分类似的属性和办法length
action
loction
( pathname | search | hash | state )push(path, [state])
replace(path, [state])
go(n)
goBack()
goForward()
block(prompt)
5.3 react-router 相干API
5.3.1 路由组件 BrowserRouter 和 HashRouter
BrowserRouter
(history模式) 和HashRouter
(hash模式)作为路由配置的最外层容器,是两种不同的模式,可依据须要抉择。// history 模式:class App extends Component {render() { return ( <BrowserRouter> <Header /> <Route path='/' exact component={Home}></Route> <Route path='/login' exact component={Login}></Route> <Route path='/detail/:id' exact component={Detail}></Route> </BrowserRouter> )}}// hash 模式:class App extends Component {render() { return ( <HashRouter> <Header /> <Route path='/' exact component={Home}></Route> <Route path='/login' exact component={Login}></Route> <Route path='/detail/:id' exact component={Detail}></Route> </HashRouter> )}}
5.3.2 门路匹配组件: Route 和 Switch
Route
: 用来管制门路对应显示的组件
参数:path
: 指定跳转门路exact
: 准确匹配路由component
: 路由对应组件render
: 通过写render函数返回具体的dom或组件location
: 与以后历史记录地位以外的地位相匹配,则此性能在路由过渡动效中十分有用sensitive
:是否辨别路由大小写strict
: 是否配置路由前面的 '/'Switch
: 渲染与该地址匹配的第一个子节点<Route>
或者<Redirect>
。相似于选项卡,只是匹配到第一个路由后,就不再持续匹配<Switch> <Route path='/home' component={Home}></Route> <Route path='/login' component={Login}></Route> <Route path='/detail' exact component={detail}></Route> <Route path='/detail/:id' component={detailId}></Route> <Redirect to="/home" from='/' /> </Switch>
留神上述的
path='/detail/:id'
,当路由为/detail/1
时,若不加exact
,则只会匹配渲染path='/detail'
路由,增加只会,才会正确地渲染path='/detail/:id'
路由。5.3.3 导航组件: Link 和 NavLink
Link
和NavLink
都能够用来指定路由跳转,NavLink
的可选参数更多。NavLink
能够看做 一个非凡版本的Link
,当它与以后 URL 匹配时,为其渲染元素增加款式属性。<Link to='/login' activeClassName="selected"> <span>登录</span></Link><NavLinkto="/login"activeStyle={{ fontWeight: 'bold', color: 'red' }}> <span>登录</span></NavLink>
5.3.4 导航组件: Redirect
<Redirect>
将导航到一个新的地址。即重定向。<Switch> <Route path='/home' exact component={Home}></Route> <Route path='/login' exact component={Login}></Route> <Redirect to="/home" from='/' exact /> </Switch>
下面,当拜访路由
/
时,会间接重定向到/home
。<Redirect>
常用语用户登录class Center extends PureComponent { render() { const { loginStatus } = this.props; if (loginStatus) { return ( <div>集体核心</div> ) } else { return <Redirect to='/login' /> } }}
5.3.5 其余
withRouter
函数withRouter
函数能够将一个非路由组件包裹为withRouter
高阶路由组件,使这个非路由组件也能拜访到以后路由的match
,location
,history
对象。不管组件何时渲染,withRouter
总会将最新的match
,location
,history
通过props
传递给这个被封装的组件。import React from "react";import PropTypes from "prop-types";import { withRouter } from "react-router";// A simple component that shows the pathname of the current locationclass ShowTheLocation extends React.Component { static propTypes = { match: PropTypes.object.isRequired, location: PropTypes.object.isRequired, history: PropTypes.object.isRequired }; render() { const { match, location, history } = this.props; return <div>You are now at {location.pathname}</div>; }}// Create a new component that is "connected" (to borrow redux// terminology) to the router.const ShowTheLocationWithRouter = withRouter(ShowTheLocation);
match
对象match
对象蕴含了<Route>
对以后URL的匹配状况,蕴含以下属性:params
: 动静路由的key-value
匹配对isExact
: 如果精准匹配上了,没有多余的结尾字符,为truepath
: path匹配表达式,<Route>
时有用url
: url 匹配串,<Link>
时有用// 如果获取match对象Route component as this.props.matchRoute render as ({ match }) => ()Route children as ({ match }) => ()withRouter as this.props.matchmatchPath as the return valueuseRouteMatch as the return value
location 对象
{ key: 'ac3df4', // not with HashHistory! pathname: '/somewhere', search: '?some=search-string', hash: '#howdy',
[userDefined]: true, }}``` 咱们在应用导航组件时,常常用 path 字符串来表述要跳转的地址,但当咱们须要传递额定参数时,location对象就能够发挥作用了。如:```JavaScript// usually all you need<Link to="/somewhere"/>// but you can use a location insteadconst location = { pathname: '/somewhere', state: { fromDashboard: true }}<Link to={location}/><Redirect to={location}/>history.push(location)history.replace(location)```
第6章: Redux
6.1 初识Redux
Redux 是专门用于做状态治理的JS库,并不是React的插件库,angular\vue中也能够应用。它能够集中式治理 React 利用的多个组件共享状态。当利用中多个组件须要共享并治理某些状态时,能够用到Redux。比方利用的主题theme治理、音乐类利用的以后歌曲列表治理等。
redux的工作流程如下:
6.2 redux的外围API
6.2.1 createStore()
其作用是创立蕴含指定 reducer
的 store
对象
import { createStore } from 'redux'import myReducer from 'mypathtoreducer'const store = createStore(myReducer)
6.2.2 store对象
store
是 Redux 库最外围的治理对象,它外部保护 state
和 reducer
,提供 getState()
dispatch(action)
subscribe(listener)
三个外围办法用于治理状态
6.2.3 applyMiddleware()
applyMiddleware()
是利用于 Redux 的中间件
import { createStore } from 'redux'import thunk from 'redux-thunk' // 以异步中间件为例import myReducer from 'mypathtoreducer'const store = createStore({ myReducer, applyMiddleware(thunk) // 利用异步中间件})
6.2.4 combineReducers()
combineReducers()
的作用是合并多个 reducer
函数
export default combineReducers({ reducerA, reducerB ...})
6.3 redux的三个外围概念
6.3.1 action
action
是要执行的行为对象,蕴含 type
标记属性和行为数据属性,如:
const ADD_POST = 'APP/ADD_POST'const action = { type: ADD_POST, payload: { post: { content: '111' } }}// 创立 action 的工厂函数会返回一个actionconst addPost = (post) => ({ type: ADD_POST, payload: { post: { content: '111' } }})
6.3.2 reducer
reducer
依据老的 state
和 action
,进行解决,并返回新的 state
export default function addPost(initialState = [], action) { switch (action.type) { case ADD_POST: return [].concat(action.payload.post).concat(initialState) default: return initialState }}
6.3.3 store
store
是将 state
, action
, reducer
分割到一起的对象
import { createStore } from 'redux'import myReducer from 'mypathtoreducer'const store = createStore(myReducer)
store
提供如下api供咱们治理状态:
getState()
获取state
dispatch(action)
散发action
, 触发reducer
,即可改版state
subscribe(listener)
注册监听,当产生新的state
时主动调用6.3.4 redux的问题
查看示例后,咱们发现:
- Redux 与 React 组件的代码耦合度太高
- 编码不够简洁
6.4 react-redux
6.4.1 初始 react-redux
react-redux 是专门用于简化 react 利用中的 redux 应用状况的一个 react 插件库。其将组建分为两类:
- UI 组件:只负责从 props 中接收数据并进行 UI 的出现,而不带有任何业务逻辑,不须要应用到 Redux 的API
容器组件: 负责管理数据和业务逻辑,不负责 UI 的出现,会波及到 Redux 的相干 API
6.4.2 react-redux 的API
Provider
让所有被包裹的组件都能够失去state数据import { Provider } from 'react-redux'<Provider store={store}> <APP /></Provider>
connect()
connect() 办法用于包装 UI 组件生成容器组件import { connect } from 'react-redux'export default connect(mapStateToProps, mapDispatchToProps)(Counter)
- mapStateToProps()
将内部的数据(即 state 对象)转换为UI组件的 props 属性,这样在组件外部想要获取 redux 中的 state 时,调用 props 即可 mapDispatchToProps()
将散发 action 的函数转换为 UI 组件的 props 属性,能够在组件内通过调用 props 办法属性的模式散发 actionimport { connect } from 'react-redux'class Counter extends React.Component { componentWillMount () { this.props.onLoad() } render () { let value = this.props.value return (...) }}const mapStateToProps = (state) => ({ value: state.value})const mapDispatchToProps = (dispatch) => ({ onLoad: addPost})export default connect(mapStateToProps, mapDispatchToProps)(Counter)
6.4.3 存在的问题
Redux 默认是不能进行一步解决的, 当利用中的确须要在 Redux 中执行异步工作时,能够抉择适合的插件来实现,如 saga redux-thunk