Hook
能够 在不编写 class 的情况下使用 state 以及其他的 React 特性。
Hook 是一个特殊的函数,它可以让你“钩入”React 的特性
作用:
能减少不停的复用一个有状态的组件
有效处理生命周期钩子函数里的逻辑混乱
解决class 中 this 指向问题
State Hook
useState 是 React 自带的一个 Hook 函数,它的作用就是用来声明状态变量。
useState 这个函数接收的参数是我们的状态初始值,它返回了一个数组,这个数组的第 0 项是当前的状态值,第 1 项是可以改变状态值的方法函数。
在一个组件中,可以使用多个 state 变量
let [stuName, setStuName] = useState('');
let [stuAge, setStuAge] = useState('');
Effect Hook
useEffect 是声明周期函数钩子的集合体,结合了componentDidMount,componentDidUpdate 和 componentWillUnmount
在书写有状态组件时,通常会产生很多的副作用
副作用(Side Effect)是指一个 function 做了和本身运算返回值无关的事,比如:修改了全局变量、修改了传入的参数、甚至是 console.log(),所以 ajax 操作,修改 dom 都是算作副作用的;
给 useEffect 传了一个匿名函数,这个匿名函数就是副作用
// useEffect专门用来处理副作用(除渲染以外的其他事)
useEffect(() => {
axios.get('http://localhost:3006/users').then(function ({ data }) {
setStu(stu = data);
})
console.log("执行了副作用", stu);
}, []);
// 后接依赖 没有依赖则为[]
需要清除的 effect
对 effect 的副作用进行解绑
给 useEffect 的副作用函数返回一个新的函数即可。这个新的函数将会在组件下一次重新渲染之后执行
useEffect(() => {
console.log(count);
return function cleanup(){
console.log('该函数会在下一次渲染之后,执行副作用函数之前执行');
}
});
跳过不必要的副作用函数
给 useEffect 传第二个参数即可。用第二个参数来告诉 React 只有当这个参数的值发生改变时,才执行我们传的副作用函数(第一个参数)
useEffect(() => {
console.log('副作用函数执行');
},[count1,count2]);
useContext
const value = useContext(MyContext);
可以实现父组件直接向指定的子组件传递数据
接收一个 context 对象(React.createContext
的返回值)并返回该 context 的当前值。当前的 context 值由上层组件中距离当前组件最近的 <MyContext.Provider>
的 value
prop 决定。
当组件上层最近的 <MyContext.Provider>
更新时,该 Hook 会触发重渲染,并使用最新传递给 MyContext
provider 的 context value
值。
useCallback
控制缓存,可以设置缓存条件
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
useMemo
类似于计算属性,只有依赖的值发生变化,才会被触发。
没有使用 useMemo 之前,getNum 方法必然会被重新调用,尽管它只是和 count 有关系,但是修改 val 的值时,该方法也会被调用
function getNum() {
console.log('已调用');
return count;
}
useMemo和useCallback
useMemo 和 useCallback 接收的参数都是一样,第一个参数为回调,第二个参数为要依赖的数据
共同作用:
1.仅仅依赖数据发生变化,才会重新计算结果,也就是起到缓存的作用。
两者区别:
1.useMemo 计算结果是 return 回来的值, 主要用于缓存计算结果的值。应用场景如:需要计算的状态
2.useCallback 计算结果是函数, 主要用于缓存函数,应用场景如: 需要缓存的函数,因为函数式组件每次
任何一个 state 的变化,整个组件都会被重新刷新,一些函数是没有必要被重新刷新的,此时就应该缓存起来,
提高性能,和减少资源浪费。
useRef
用于非受控组件的创建
非受控组件也可以使用 createRef 方法来创建一个 ref
const inputElememnt1 = React.createRef();
而 useRef 本质上也是创建一个 ref
const inputElememnt2 = useRef();
useRef 与 createRef 的区别:
使用 createRef 创建的 ref,每一次视图更新,都会重新创建一个新的 ref,然后这个 ref 和表单控件相关联
useRef 只会在第一次创建,之后视图更新不会创建一个新的
若打印两个 ref 值,会发现 createRef 每次都是重新生成 ref,然后指向 input 元素,而 useRef 则是只生成一次,后面就一直指向上一次的 input 元素
Hook 规则
只在最顶层使用 Hook 钩子函数
不要在循环,条件或嵌套函数中调用 Hook
确保 Hook 在每一次渲染中都按照同样的顺序被调用
只在 React 函数中调用 Hook 钩子函数
不要在普通的 JavaScript 函数中调用 Hook
前端路由与后端路由
后端路由:
在服务端设置的路由,前端发出请求,服务端解析请求,分析要跳转的页面,除了hash和history模式,任何跳转都会触发请求。配置页面与页面的关系
前端路由:
来设定显示什么模块,比如通过hash # 后接模块路径,来指定地显示页面,并不会向服务端发起请求。 配置模块与页面的关系
React Router
是官方提供的一个与 React 配套使用的前端路由库
它利用 HTML 5 的 history API,来实现组件的切换
使用前先安装 react-router-dom
npm install react-router-dom
在 ndex.js 中,从 react-router-dom 导入 BrowserRouter 和 HashRouter 组件。
BrowserRouter 使用的是基于 HTML 5 的 History API,浏览器提供相应的接口来修改浏览器的历史记录
HashRouter 是通过改变地址后面的 hash 来改变浏览器的历史记录
在根组件 App.js。我们分别引入 Route,Switch ,Link 以及 Redirect
import {Link, Route, Switch, Redirect} from 'react-router-dom'
Route 组件用于定义路由匹配上后映射到哪一个组件
Switch 用于包裹 Route,表示匹配众多 Route 中的其中一个
Redirect 表示一开始就重定向到 about 路由
嵌套路由
不同的组件中,可以嵌套很多层
在对应的组件下,同配置路由一样的步骤,即可实现嵌套
向路由组件传递参数
获取到当前的路由
props.match.path
在父组件中
<div key={item.id}><Link to={`${path}/${item.id}`}>{item.title}</Link></div>
// 通过 :id 来传递参数
<Route path={`${path}/:id`} component={MessageDetail}></Route>
子组件可以通过路由拿到传递过来的id
props.match.params.id
编程式导航
使用 js 代码来实现路由的跳转
相应路由的跳转
this.props.history.push(`/home/message/${id}`)
路由的替换
this.props.history.replace(`/home/message/${id}`)
返回上一个路由
this.props.history.goBack()
前进到下一个路由
this.props.history.goForward()
Redux
vuex 是 vue 的状态管理器
而 Reaux 则可以与 React 进行良好的配合
Redux 是 JavaScript 应用的状态容器,提供可预测化的状态管理。
一个成型的产品是由 组件和状态 共同 组成的
Redux 和 React 的关系
两者之间没有任何关系
Redux 同样可以与 jQuery 等类库搭配使用,也可以应用于 Vue、Angular 等其他框架所搭建的应用里面
Redux 只是 作为一个应用数据流架构,能和 React 完美结合
Redux 设计哲学
Single source of truth 单一真相
单一真相:所有组件都放在仓库里面,只需在仓库中取数据
页面状态数据树被存储为一个 JavaScript 对象,此时状态数据树是会随着用户的操作或者异步数据的到达等变化而发生变更的。
let state = store.getState();
缓解,各个组件的状态数据依赖关系
State is read-only
所有的状态数据存储在一个 JavaScript 对象中,通过 store.getState 方法获取,而这个对象是只读的
只读 是指 当页面需要新的数据状态时再生成一棵全新的状态数据树,使得 store.getState 方法返回一个全新的 JavaScript 对象。
需要 dispatch(派发)一个 action (动作/事件)即可,action传入 reducer。这个 action 其实也是一个 JavaScript 对象,用于描述这个动作单元变化的所有信息。
Changes are made with pure functions called reducer
使用 reducer 函数来接收 action,并执行页面状态数据树的变更
educer 接收 2 个参数
- 当前页面数据状态
- 被派发的 action
延伸:什么是reducer
在数组有一个方法叫做 reduce,该方法是一种运算合成,它通过遍历、变形、累积,将数组的所有成员“累积”为一个值。
在 Redux 数据流里,reducer 在具备初始状态的情况下,每一次运算其实都是根据之前的状态(previous state)和现有的 action (current action)来更新 state 的
每次 reducer 被执行时,state 和 action 都被传入,这个 state 根据 action 进行累加,进而返回最新的 state。
纯函数
reducer 就是一个纯函数
纯函数代表这类函数:
对于指定输出,返回指定结果
不存在副作用
纯函数的回值只依赖其参数
纯函数内不能存在任何副作用
调用系统 I/O 的 API,例如 Date.now 或者 Math.random 等方法
发送网络请求
在函数体内修改外部变量的值
使用 console.log 等方法输出信息
调用存在副作用的函数等
redux文件夹下的文件管理
sctions.js :工厂函数 ,专门负责创建 action 对象的
reducers.js :是一个纯函数,接收传递过来的 action 对象
store.js :负责仓库文件
type.js : 统一管理 action 里的Type,以便于后期的维护管理