前端 | React 学习笔记
1. 什么是React
React用于构建 Web 和原生交互界面的库,可以将数据渲染为HTML视图的开源JS库
React用来构建界面的JavaScript库,只提供了UI层面的解决方案,遵循组件设计模式,声明式编程规范和函数式编程概念。使用虚拟 DOM 来操作真实 DOM 来提高应用程序的效率。
2. React特点有哪些
- 采用组件化模式、声明式编程,提高开发效率以及组件的复用率。
- 在React Native 中可以使用React语法进行移动端开发。
- 使用虚拟DOM以及优秀的Diffing算法,尽量减少与真实DOM的交互。
3. React优点有哪些
- 提高了应用的性能
- 基于使用 JSX,代码的可读性更好
4. React 简单应用Hello, React
项目操作步骤:
- cdn.bootcdn.net 搜索
react、react-dom、babel
- 编写Html页面,引入React 核心库、操作 DOM 的 react 扩展库、将 jsx 转为 js 的 babel 库
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>01_Hello React</title>
</head>
<body>
<div id="test"></div>
<script type="text/javascript" src="./js/16.9.0/react.development.js"></script>
<script type="text/javascript" src="./js/16.9.0/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script></script>
<script type="text/babel">
const visualDom = <h1>Hello,React</h1>
ReactDOM.render(visualDom, document.querySelector("#test"))
</script>
</body>
</html>
- 引入核心库等内容必不可少
script标签中的type=“text/babel”表示不编写原生的JavaScript(type="text/javascript")ReactDOM.render(reactNode, domNode, callback?)参照官网方法 zh-hans.react.dev/reference/r…
项目执行结果:
- 16.9.0版本的React执行结果与控制台输出
- 17.0.2版本的React执行结果与控制台输出
- 18.2.0版本的React执行结果与控制台输出
JSX(JavaScriptXML)
JSX(JavaScriptXML)是一种用于React项目的JavaScript语法扩展,并不是全新的编程语言,而是一个语法糖,使得编写React组件时的代码更加直观和易于维护。
- 定义虚拟DOM,不能使用双引号
“” - 标签中混入JS表达式的时候使用
{} - 样式的类名指定不能使用class,使用
className - 内敛样式要使用
{{}}包裹,style={{color:'red'}} - 不能有多个根标签,只能有一个根标签
- 标签必须闭合
<div></div>,自闭合也行<input /> - 小写字母开头,就将标签转化为 html 同名元素,html 中无该标签对应的元素就报错
- 大写字母开头,react 就去渲染对应的组件,没有找到组件就报错
虚拟DOM
1. 认识虚拟DOM
虚拟DOM (Virtual DOM) 是一种轻量级的抽象,它允许我们在JavaScript中创建、更新和删除DOM元素。它是React等现代JavaScript框架的核心概念之一。
- 虚拟DOM的工作原理是:当状态改变时,React会重新渲染整个DOM树,并比较新旧树的差异。然后,React只会更新实际DOM中发生变化的部分,而不是整个DOM树。
虚拟DOM的优点:
- 减少重绘的次数,提高性能。
- 跨平台,因为虚拟DOM可以在Web、服务器和本地应用中使用。
- 使用JSX,可以更容易地写出类似HTML的代码。
2. 使用JSX创建虚拟DOM
<script type="text/babel">
const visualDom = <h1>Hello,React</h1>
console.log(visualDom);
ReactDOM.render(visualDom, document.querySelector("#test"))
</script>
- 输出虚拟DOM,发现虚拟DOM是一个对象
3. 使用JS创建虚拟DOM
<script type="text/babel">
const visualDom2 =React.createElement('h1',{id:'title'},React.createElement('span',{},'hello,React'))
console.log(visualDom2);
ReactDOM.render(visualDom2, document.querySelector("#test"))
</script>
- JS写法在创建更多层级时,就会显得特别繁琐臃肿,不好维护。建议一直使用JSX的,符合书写习惯
Diff 算法
为了避免不必要的渲染,按需更新,虚拟DOM会采用Diff算法进行虚拟DOM节点比较,比较节点差异,从而确定需要更新的节点,再进行渲染。
面试题:
动态表单的数据添加内容,在对应的源数据后的输入框输入内容
class Animal extends React.Component {
state = {
formList: [{
key: 1,
name: '张三'
}, {
key: 2,
name: '李四'
}, ]
}
componentWillMount() {
console.log("componentWillMount")
}
render() {
const { formList } = this.state;
console.log(formList)
const addPerson = () => {
this.setState({
formList: [ ...[ { key:3, name: '王五' }], ...formList,]
})
}
return <div>
111
<ul>
{
formList.map((item, index)=>{
return <li key={index}>{item.name}<input /> </li>
})
}
</ul>
<button onClick={ addPerson } >新增</button>
</div>
}
}
第一种结果:
第二种结果:
5.React组件
组件,React 内部创建组件的实例对象,调用 render() 得到虚拟DOM,并解析为真实的DOM,插入到指定元素内部。
注意:
- 组件名必须是首字母大写
- 虚拟DOM元素只能有一个根元素
- 虚拟DOM元素必须有结束标签
< />
1. 函数式组件
- 通过定义函数,返回JSX的虚拟DOM的函数,称为函数式组件
2. 类组件
- 通过继承(
extends React.Component)定义的类,称为类组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>02_函数组件与类组件</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="./js/16.9.0/react.development.js"></script>
<script type="text/javascript" src="./js/16.9.0/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>
<script type="text/babel">
// 类组件
class Animal extends React.Component {
render() {
return <div>
动物园里有什么
<Dog />
</div>
}
}
// 函数组件
function Dog() {
return <div>
狗:汪汪汪
</div>
}
ReactDOM.render( <Animal />, document.getElementById("root"));
</script>
</body>
</html>
3. 受控组件
-
受控组件:表单组件的输入组件随着输入并将内容存储到状态中(
随时更新)- onChange 回调方法,维护数据到状态中,类似VUE的双向绑定
<script type="text/babel">
//创建组件
class Login extends React.Component{
//初始化状态
state = {
username:'', //用户名
password:'' //密码
}
//保存用户名到状态中
saveUsername = (event)=>{
this.setState({username:event.target.value})
}
//保存密码到状态中
savePassword = (event)=>{
this.setState({password:event.target.value})
}
//表单提交的回调
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this.state
alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
}
render(){
return(
<form onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} type="text" name="username"/>
密码:<input onChange={this.savePassword} type="password" name="password"/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
</script>
4. 非受控组件
-
非受控组件:表单组件的输入组件的内容现用现取(
即用即取)- 通过
form、ref等内容,由真实DOM获取数据,不维护到状态中
- 通过
<script type="text/babel">
//创建组件
class Login extends React.Component{
handleSubmit = (event)=>{
event.preventDefault() //阻止表单提交
const {username,password} = this
alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
}
render(){
return(
<form onSubmit={this.handleSubmit}>
用户名:<input ref={c => this.username = c} type="text" name="username"/>
密码:<input ref={c => this.password = c} type="password" name="password"/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
</script>
5. 组件实例三大属性 state props refs
1. state
- 组件的状态,也就是该组件所存储的数据
- React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
定义 state
在类组件中定义state,state是对象({})
- 在构造器中初始化
state,(this.state={ version: '1.0.0'}) - 在类中添加属性
state来初始化,(state = { version: '1.0.0'})
使用 state
const { version } = this.state;
修改 state
在类组件中修改state,使用setState()方法,合并属性。
-
this.setState(partialState, [callback]);partialState: 需要更新的状态的部分对象callback: 更新完状态后的回调函数
-
直接修改
this.setState({
version: '1.1.0'
})
- 依据原参数修改
// 传入一个函数,返回x需要修改成的对象,参数为当前的 state
this.setState(state => ({count: state.count+1});
2. props
state是组件自身的状态,而props则是外部传入的数据
定义 props
- 通过在组件标签上传递值,在组件中就可以获取到所传递的值
- 在构造器里的
props参数里可以获取到props
使用 props
const { name, age, sex } = this.props;
修改 props
- 需要借助外部方法修改 props
检查 props
- 凡是入参都会有校验,前端也不例外
- 设置
propTypes定义props的规范,添加在类式组件的原型对象 - 设置
defaultProps定义props的默认值,添加在类式组件的原型对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>02_函数组件与类组件</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="./js/16.9.0/react.development.js"></script>
<script type="text/javascript" src="./js/16.9.0/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>
<script type="text/javascript" src="./js/prop-types.js"></script>
<script type="text/babel">
// 类组件
class Animal extends React.Component {
render() {
const { aniName, aniCount } = this.props;
return <div>
动物园里有什么
<br/>
{`动物园里有 ${aniName},${aniCount}只`}
</div>
}
static propTypes = {
aniName: PropTypes.string.isRequired,
aniCount: PropTypes.number
}
static defaultProps = {
aniCount: 0
}
}
// 函数组件
function Dog() {
return <div>
狗:汪汪汪
</div>
}
ReactDOM.render( <Animal aniName='老虎' />, document.getElementById("root"));
</script>
</body>
</html>
注意:
- 组件代码中增加
propTypes和defaultProps
3. refs
- Refs 提供了一种方式,允许我们访问 DOM 节点或在
render方法中创建的 React 元素。
何时使用Refs
- 管理焦点,文本选择或媒体播放。
- 触发强制动画。
- 集成第三方DOM库。
在React无法控制局面的时候就需要直接操作Refs了。
Refs有哪些使用方式
-
字符串形式的refs。(可能在以后的版本中弃用)
-
回调形式的refs。
- 组件实例的
ref属性传递一个回调函数c => this.input1 = c(箭头函数简写),这样会在实例的属性中存储对DOM节点的引用,使用时可通过this.input1来使用
- 组件实例的
-
使用React.createRef()创建,并通过ref属性附加到React元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>02_函数组件与类组件</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="./js/16.9.0/react.development.js"></script>
<script type="text/javascript" src="./js/16.9.0/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>
<script type="text/javascript" src="./js/prop-types.js"></script>
<script type="text/babel">
// 类组件
class Animal extends React.Component {
myRef = React.createRef()
showData=()=>{
console.log(this.refs.input1)// 通过字符串形式拿到标签为input1的真实DOM
console.log(this.refs.input1.value)
}
showDataFun =()=>{
console.log(this.inputFun)// 通过回调函数方式拿到声明的实例属性 inputFun 拿到真实的DOM
console.log(this.inputFun.value)
}
showDataCreate =()=>{
console.log(this.myRef) // 通过 cerateRef() 创建,拿到指定的 ref 的真实 DOM
console.log(this.myRef.current.value)
}
render() {
const { aniName, aniCount } = this.props;
return <div>
动物园里有什么
<br/>
{`动物园里有 ${aniName},${aniCount}只`}
<div>
<input ref='input1' type="text" placeholder='点击按钮提示数据'/>
<button onClick={this.showData}>点我提示左侧数据</button>
</div>
<div>
<input ref={(currentNode)=>{this.inputFun=currentNode}} type="text" placeholder='点击按钮提示数据' />
<button onClick={this.showDataFun}>点我提示左侧数据</button>
</div>
<div>
<input ref={this.myRef} type="text" placeholder='点击按钮提示数据' />
<button onClick={this.showDataCreate}>点我提示左侧数据</button>
</div>
</div>
}
static propTypes = {
aniName: PropTypes.string.isRequired,
aniCount: PropTypes.number
}
static defaultProps = {
aniCount: 0
}
}
// 函数组件
function Dog() {
return <div>
狗:汪汪汪
</div>
}
ReactDOM.render( <Animal aniName='老虎' />, document.getElementById("root"));
</script>
</body>
</html>
6. 事件处理
- React 使用的是自定义事件,而不是原生的 DOM 事件,通过
onXxx属性指定时间处理函数 - React 的事件是通过事件委托方式处理的(为了更加的高效)
- 可以通过事件的
event.target获取发生的 DOM 元素对象,可以尽量减少refs的使用
<input onChange={this.saveName} type="text" name="username" />
saveName = (event) => {
this.setState({name: event.target.value});
}
6. 生命周期
- React 生命周期主要包括三个阶段:初始化阶段,更新阶段,销毁阶段
- projects.wojtekmaj.pl/react-lifec…
在 React 16、17与18中组件的生命周期有所不同,主要变化在于旧的生命周期被新的生命周期钩子函数所替代,并且新React版本中推荐使用函数组件的Hooks来替代组件的生命周期函数。
16 版本之前的生命周期
-
初始化阶段:由 ReactDOM.render() 触发,进行初次渲染
-
检查组件中是否有默认的属性()、是否有属性校验()
-
constructor()
-
componentWillMount()
- 组件即将挂载到页面上
-
render()
- 渲染页面
-
componentDidMount()
- 组件已经被挂载到页面中
-
-
更新阶段:由组件内部
this.setState()或父组件render触发渲染-
componentWillReceiveProps()
- 父组件改变了
props的值
- 父组件改变了
-
shouldComponentUpdate()
- state 被更改时触发,接收两个参数为 nextProps、nextStates
return false不更改,流程回到state被更改前return true进行更改,state更改,流程继续
-
componentWillUpdate()
- 执行
conponentWillUpdate生命周期函数,告知组件即将开始进行更新
- 执行
-
render()
-
componentDidUpdate()
- 执行
componentDidUpdate生命周期函数,告知组件更新并渲染完毕。 - 此时更新过的组件已经渲染到页面中
- 执行
-
-
卸载阶段:由
ReactDOM.unmountComponentAtNode()触发-
componentWillUnmount()
- 即将销毁组件
-
-
异常处理
- componentDidCatch()
17 版本之后的生命周期
eg.17.0.2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>04_旧版本生命周期</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="./js/17.0.2/react.development.js"></script>
<script type="text/javascript" src="./js/17.0.2/react-dom.development.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>
<script type="text/javascript" src="./js/prop-types.js"></script>
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log("count-constructor")
super(props)
// 初始化状态
this.state = {
count: 0
}
}
// 将要挂载
UNSAFE_componentWillMount() {
console.log("UNSAFE_componentWillMount")
}
//挂载完毕
componentDidMount() {
console.log("componentDidMount")
}
// +1 按钮回调
add = () => {
//获取原状态
const { count } = this.state
// 更新状态
this.setState({ count: count + 1 })
}
// 卸载组件的回调
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('root'))
}
// 组件将要卸载调用
componentWillUnmount() {
console.log("componentWillUnmount")
}
UNSAFE_componentWillReceiveProps (){
console.log("UNSAFE_componentWillReceiveProps ")
}
// 控制组件更新的“阀门”
shouldComponentUpdate() {
console.log("shouldComponentUpdate")
return true
}
// 组件将要更新的钩子
UNSAFE_componentWillUpdate() {
console.log("UNSAFE_componentWillUpdate")
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log("componentDidUpdate")
}
force = () => {
this.forceUpdate()
}
render() {
console.log("count-render")
return (
<div>
<h1>当前求和为{this.state.count}</h1>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>销毁</button>
<button onClick={this.force}>强制更新</button>
</div>
)
}
}
ReactDOM.render( <Count />, document.getElementById("root"));
</script>
</body>
</html>
- 初始阶段,仍使用
componentWillMount()、componentWillReceiveProps()、componentWillUpdate()
- 初始阶段,使用新
UNSAFE_componentWillMount()、UNSAFE_componentWillReceiveProps()、UNSAFE_componentWillUpdate()
- 更新阶段
- 卸载阶段
18 版本的生命周期
eg.18.2.0
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>04_旧版本生命周期</title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="./js/18.2.0/react.development.min.js"></script>
<script type="text/javascript" src="./js/18.2.0/react-dom.development.min.js"></script>
<script type="text/javascript" src="./js/babel.min.js"></script>
<script type="text/javascript" src="./js/prop-types.js"></script>
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log("count-constructor")
super(props)
// 初始化状态
this.state = {
count: 0
}
}
// 将要挂载
UNSAFE_componentWillMount() {
console.log("UNSAFE_componentWillMount")
}
//挂载完毕
componentDidMount() {
console.log("componentDidMount")
}
// +1 按钮回调
add = () => {
//获取原状态
const { count } = this.state
// 更新状态
this.setState({ count: count + 1 })
}
// 卸载组件的回调
death = () => {
// ReactDOM.unmountComponentAtNode(document.getElementById('root'))
root.unmount();
}
// 组件将要卸载调用
componentWillUnmount() {
console.log("componentWillUnmount")
}
UNSAFE_componentWillReceiveProps (){
console.log("UNSAFE_componentWillReceiveProps ")
}
// 控制组件更新的“阀门”
shouldComponentUpdate() {
console.log("shouldComponentUpdate")
return true
}
// 组件将要更新的钩子
UNSAFE_componentWillUpdate() {
console.log("UNSAFE_componentWillUpdate")
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log("componentDidUpdate")
}
force = () => {
this.forceUpdate()
}
render() {
console.log("count-render")
return (
<div>
<h1>当前求和为{this.state.count}</h1>
<button onClick={this.add}>点我+1</button>
<button onClick={this.death}>销毁</button>
<button onClick={this.force}>强制更新</button>
</div>
)
}
}
// ReactDOM.render( <React.StrictMode><Count /></React.StrictMode>, document.getElementById("root"));
// ReactDOM.render( <Count />, document.getElementById("root"));
const container = document.getElementById("root");
const root = ReactDOM.createRoot(container);
root.render(<Count />);
</script>
</body>
</html>
- 渲染无问题,按照内容修改
- 卸载阶段问题与解决办法
7. 脚手架
1. 使用create-react-app创建react应用
脚手架介绍
react提供了用于创建react项目的脚手架库:create-react-app- 项目的整体架构为:react + webpack + es6 + eslint
- 包含了所有需要的配置,语法检查、JSX编译、devServer……
创建并启动项目
- 安装 - 执行 - 启动
- 全局安装脚手架
npm install -g create-react-app - 使用命令创建项目
create-react-app hello-react-01 - 进入项目目录并启动项目
cd hello-react-01 && npm start
脚手架项目结构
- public 静态资源文件夹
- src 源码文件夹
2. VSCODE中react插件的安装
- ES7 React/Redux/GraphQL/React-Native snippets
3. 脚手架项目的应用
组件间数据传递
- 在React中,组件间数据传递通常通过props(属性)和state(状态)来实现。
父传子
子传父
消息订阅与发布
-
依赖库**
PubSubJS** -
下载
npm install pubsub-js --save -
使用
- 引入
import PubSub from 'pubsub-js' - 订阅
PubSub.subscribe('add', function(data){}) - 发布
PubSub.publish('add', data)
- 引入
路由
单页面应用
- 单页Web应用(SPA,single page web application)
- 整个页面只有一个完整的页面
- 在页面只做局部更新
路由的理解
- 路由就是路径与组件的映射关系
- 后端路由:node 接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。
- 前端路由:浏览器的路径 path 改变时,路由的组件随着改变
路由使用react-router-dom
- 导航栏使用
<Link to="/h1t">标题1</Link> - 展示组件使用
Route进行路径匹配<Route path="h1t" component={ H1title}/> - 导航栏和展示组件需要在同一个
Router中,可以是<BrowserRouter>或<HashRouter>
<BrowserRouter>或<HashRouter>的区别
-
底层原理不一样
<BrowserRouter>使用H5的 history API,不兼容 IE9 及以下版本<HashRouter>使用的是 URL 的哈希值
-
URL表现形式不一样
<BrowserRouter>路径不带 #<HashRouter>路径带 #
-
刷新后对路由
state参数的影响<BrowserRouter>无影响,state 保存在 history 对象中<HashRouter>刷新导致 state 参数丢失
路由组件与一般组件
-
写法不同
- 路由组件:
<Route path="/index" component={IndexPage} /> - 一般组件:
<Demo />
- 路由组件:
-
接收数据不同
-
一般组件:依靠标签传递内容
-
路由组件:默认有三个固定的属性
-
history:
- go: f go(n)
- goBack: f goBack()
- goForward: f goForward()
- push: f push(path, state)
- replace: f replace(path, state)
-
location:
- pathname: "/index"
- search: ""
- state: undefined
-
match:
- params: {}
- path: "/index"
- url: "/index"
-
-
路由组件API
-
通过
<NavLink>可以实现路由切换的高亮显示,使用属性activeClassName可以指定高亮样式 -
注册路由使用
<Switch>包裹,使path和component保持一对一的关系,并且可以提高路由匹配效率 -
路由默认采用的是模糊匹配,可以开启严格匹配(
路由上增加 exact={true}),一级路由开启严格匹配,可能会导致无法继续匹配二级路由 -
使用
<Redirect to="/index" />将页面重定向到指定的路由组件中 -
嵌套路由
- 注册子路由时,需要写上父路由的
path值 - 路由的匹配是按照注册路由的顺序进行的
- 注册子路由时,需要写上父路由的
路由参数传递
-
params
-
向路由组件传递参数
<Link to={``/home/message/${msg}``}>传递params参数</Link>
-
路由组件的声明
<Route path="/home/message/:msg" />
-
接收参数
this.props.match.params;
-
-
search
-
向路由组件传递参数
<Link to={``/home/message?msg=${msg}``}>传递search参数</Link>
-
路由组件的声明(无需声明,正常注册即可)
<Route path="/home/message" />
-
接收参数
this.props.location.search- 参数传递与解析,需要借助
querystring库 - 对象转urlencode编码
qs.stringify(obj) - urlencode编码转对象
qs.parse(str)
- 参数传递与解析,需要借助
-
-
state 借助浏览器的history保存数据,刷新不丢失
-
向路由组件传递参数
-
<Link to={{path: '/home/message', state: {msg: '消息1'}}>传递state参数</Link> -
路由组件的声明(无需声明,正常注册即可)
<Route path="/home/message" />
-
-
接收参数
this.props.location.state;
-
路由跳转的两种模式
- push 放入栈顶,Link、NavLink 默认跳转模式
- replace 替换栈顶
<Link replace />
编程式路由导航
- 借助
this.props.history对象的API,操作路由跳转、前进、后退
withRouter使用
-
让一般组件具备路由组件所持有特有的API
-
使用
- 引入
import { withRouter } from 'react-router-dom'; - 使用
export default withRouter(IndexPage)
- 引入
状态管理库redux
认识redux
-
redux 官网 redux.js.org/
- 中文官网:www.redux.org.cn/
- Github:github.com/reactjs/red…
-
redux是一个专门用于状态管理的JS库
-
集中管理react应用多个组件共享的状态
工作流程
redux精简版
-
新建文件夹
store,并创建文件store.js与count_reducer.js -
编写
store.js- 引入
redux中的createStore函数,创建一个store对象 createStore函数调用时需要传入一个为其服务的reducer
- 引入
-
编写
count_reducer.jsreducer本质上是一个函数,入参为(preState, action)出参为状态结果reducer进行初始化状态以及加工状态reducer被第一次调用时,是store自动触发的,传递的preState是undefined
-
在
index.js中检测store中状态的改变,一旦发生改变重新渲染<App />- redux 只负责状态管理,状态改变驱动页面的展示(重新渲染)需要我们写
import store from './redux/store'
import App from './App'
import ReactDOM from 'react-dom'
store.subscribe(() => {
ReactDOM.render(<App />, document.getElementById('root'));
})
react-redux 基本使用
-
容器组件与UI组件
- UI组件:不能使用任何
redux的api,只负责页面的呈现、交互等 - 容器组件:负责和
redux通信,将结果交给UI组件
- UI组件:不能使用任何
-
创建一个容器组件
-
connect(mapStateToProps, mapDispatchToProps)(UI组件)mapStateToProps:映射状态,返回值是一个对象mapDispatchToProps:映射操作状态的方法,返回值是一个对象
-
-
容器组件中的
store是靠props传进去的,而不是在容器组件中直接引入