React 详解【 JSX + 组件 + prop、state、ref + 事件 + 生命周期 + React Ajax + React Router路由 + Redux】
文章目录
- React 是什么
- 安装 React
- 安装步骤:
- React 中的元素渲染
- React JSX
- 使用 JSX 的好处:
- 使用 React JSX
- React 组件
- 渲染组件
- 复合组件
- 组件的三大属性(state、props、refs)
- state
- 使用 state
- 使用 state 的小案例
- props
- 作用
- 使用 props
- refs
- refs 使用的小案例
- 注意:
- 组件内的事件
- 事件函数的使用
- 组件的生命周期
- 组件三个生命周期状态
- 生命周期方法与流程
- 重要的生命周期方法
- 虚拟DOM 与 DOM Diff 算法
- React Ajax
- 说明
- 常用的 Ajax 请求库
- 在 Reate 中使用 Ajax
- Fetch
- 组件间的通信
- 消息订阅发布机制
- 使用
- React-router
- 介绍
- SPA 应用的理解
- 对路由的理解
- 路由是什么?
- 路由分类(前台路由、后台路由)
- 前台路由实现
- React-router 相关 API
- 组件
- 路由基本使用
- 嵌套路由的使用
- 向路由组件中传递参数
- Redux
- Redux 是什么
- Redux 工作流程
- 什么情况下需要使用 redux
- 对 state 进行增减的案例代码:
- react-redux
React 是什么
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
安装 React
在安装 React 之前需要安装 nodejs,之后使用 node 中的 npm 命令来搭建 Reate 运行环境
安装步骤:
-
安装 nodejs
-
安装淘宝定制的 cnpm 命令,使用 cnpm 代替 npm,速度会快很多:
$ npm install -g cnpm --registry=https://registry.npm.taobao.org
$ npm config set registry https://registry.npm.taobao.org
使用 $ cnpm install [name] 来安装你想要的模块 -
使用 create-react-app 快速构建 React 开发环境:
$ cnpm install -g create-react-app$ create-react-app my-app创建 create 项目
$ cd my-app/
$ npm start
访问 http://localhost:3000/ 即可看到效果
React 中的元素渲染
例如:
<html><head>
<meta charset="UTF-8" />
<title>Hello Reacttitle>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js">script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js">script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js">script>
head><body><div id="example">div><script type="text/babel">const element = <h1>Hello, world!</h1>;ReactDOM.render(element,document.getElementById('example'));
script>
body>html>
React 通过方法ReactDOM.render()将元素 element 渲染到 id 为 example 的标签内,当然也可同时定义多个 div 进行多次渲染,例如:
<div id="example" style="width: 100px; height: 100px; background-color: antiquewhite;">div>
<div id="example2" style="width: 100px; height: 100px; background-color:aqua">div>
<div id="example3" style="width: 100px; height: 100px; background-color:aquamarine">div><script type="text/babel">const element = <h1>Hello, world!</h1>;const element2 = <h2>Hello, world!</h2>;const element3 = <h3>Hello, world!</h3>;ReactDOM.render(element,document.getElementById('example'));ReactDOM.render(element2,document.getElementById('example2'));ReactDOM.render(element3,document.getElementById('example3'));
script>
React JSX
在 React 中使用 JSX 来替代常规的 JavaScript,例如代码const element = 就是 JSX 语言,像是传统 js 与 html 的结合,JSX 的作用就是声明 React 当中的元素,例如用变量 element 指向声明的元素,之后要使用该元素的话,直接用 element 就好了。Hello, world!
;
-
JSX 是 JavaScript 的语法扩展。 推荐在 React 中使用 JSX 来描述用户界面。
-
JSX 是在 JavaScript 内部实现的。
-
JSX 定义的元素是普通的对象,React DOM 可以确保浏览器 DOM 的数据内容与 React 元素保持一致。
使用 JSX 的好处:
- JSX 执行更快,因为它在编译为 JavaScript 代码后进行了优化。
- 它是类型安全的,在编译过程中就能发现错误。
- 使用 JSX 编写模板更加简单快速。
注意:由于 JSX 就是 JavaScript,一些标识符像 class 和 for 不建议作为属性名。作为替代,React DOM 使用 className 和 htmlFor 来做对应的属性,这是因为 class 和 for 是 JavaScript 的保留字。
使用 React JSX
- JSX 中可定义多个元素,例如:
const element = (<div><h1>Hello</h1><h2>Good to see you</h2></div>
);
- 在 JSX 中嵌入 {} 表达式,可在大括号 {} 内放置任何有效的 js 表达式,例如算式、
user.userName等等
<body>
<div id="example"></div><script type="text/babel">const user = { userName: "张三", age: "18" };const element = <h1>Hello, {user.userName}</h1>;ReactDOM.render(element,document.getElementById('example'));
</script>
</body>
效果为:

React 组件
Reate 的组件相当于 js 中的函数
- 定义方式1:看下面代码块,React 定义了一个组件,该组件接收一个
prarm参数,返回一个元素。这类组件被称为“函数组件”,因为它本质上就是 js函数。
function ReturnMessage(prarm) {return <h3>hello, {prarm.name}</h3>;
}
- 定义方式2:下面代码块使用 ES6 的 class 来定义组件,使用 class 来定义组件会有额外特性,之后介绍。
class Welcome extends React.Component {render() {return <h1>Hello, {this.props.name}</h1>;}
}
渲染组件
React 元素也可以是用户自定义的组件:const element3 = ,看以下代码块:
<body>
<div id="example3">div><script type="text/babel">function ReturnMessage(props) {return <h3>hello, {props.name}</h3>;}const element3 = <ReturnMessage name="张三" />;ReactDOM.render(element3,document.getElementById('example3'));
script>
body>
当 React 元素(JSX)为用户自定义组件时,它会将 JSX 所接收的属性(attributes)以及子组件(children)转换为单个对象传递给组件,这个对象被称之为 “props”。这段代码会在页面上渲染 hello, 张三。
注意,原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,比如 ReturnMessage不能写成 returnMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。
复合组件
看以下代码,复合组件就像层层方法调用,在 App() 中调用了 Name() 与 Age() 组件,在 ReactDOM.render() 中调用 App() 组件。
<body>
<div id="example2" style="width: 100px; height: 100px; background-color:aqua">div><script type="text/babel">const element2 = <h2>Hello, world!</h2>;ReactDOM.render(<App />,document.getElementById('example2'));function App() {return (<div><Name name="张三" /><Age age="18" /></div>);}function Name(props) {return <h6>名称:{props.name}</h6>;}function Age(props) {return <h6>年龄:{props.age}</h6>;}
script>
body>
效果:

组件的三大属性(state、props、refs)
state
-
state 是组件对象最重要的属性,值是对象(可以包含多个数据)
-
组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件),state 的值一旦被改变会触发该组件的重新渲染
使用 state
- 初始化状态:
constructor (props) {super(props)this.state = {stateProp1 : value1,stateProp2 : value2}}
-
读取某个状态值:
this.state.状态值名 -
更新状态
this.setState({stateProp1 : value1,stateProp2 : value2})
使用 state 的小案例

点击按钮,左边的数字 + 1:
<body>
<div id="example2"></div>//点击按钮,数字+1
class MyComponent2 extends React.Component {constructor(props) {super(props);this.click = this.click.bind(this);//初始化 statethis.state = { count: 0 }}click(e) {var i = this.state.count + 1;//修改 statethis.setState({count: i})}render() {return (<div><span>{this.state.count}</span> <button type="button" onClick={this.click}>+1按钮</button></div>)}
}ReactDOM.render(<MyComponent2 />, document.getElementById("example2"));
</script>
</body>
props
-
每个组件对象都会有 props(properties的简写) 属性
-
组件标签的所有属性都保存在 props 中
作用
-
通过标签属性从组件外向组件内传递变化的数据
-
注意: 组件内部不要修改 props 数据,props 具有只读性,组件无论是使用函数声明或是 class 声明,都决不能修改自身的 props。例如以下这个
sum函数:
function sum(a, b) {return a + b;
}
这样的函数被称为纯函数,因为该函数不会尝试更改入参,且多次调用下相同的入参始终返回相同的结果。所有组件都必须像纯函数一样保护它们的 props 不被更改。
使用 props
首先构建一个组件 Person:
function Person(props) {return (<ul><li>name:{props.name}</li><li>age:{props.age}</li><li>gender:{props.gender}</li></ul>)
}
要使用ReactDOM.render()将一个 person 对象传入 Person 组件中,返回相应元素;age、gender 属性要设置默认,name、age 属性的类型要被限制,以下是使用方式:
- 内部读取某个属性值
this.props.propertyName - 对 props 中的属性值进行类型限制和必要性限制:
//该方式写在组件类的外面
Person.propTypes = {name: React.PropTypes.string.isRequired,age: React.PropTypes.number.isRequired
}
//写在组件类里面的形式,static 表示给组件类指定属性
static propTypes = {name: React.PropTypes.string.isRequired,age: React.PropTypes.number.isRequired
}
- 对 props 设置默认属性值:
Person.defaultProps = {age: 20,gender: "男"
};
- 组件类的构造函数:
constructor (props) {super(props)console.log(props) // 查看所有属性
}
- 扩展属性,将对象的所有属性通过props传递:
const p1 = {name: "tom",age: 10,gender: "女"
};
// ReactDOM.render( ,
// document.getElementById("example"));ReactDOM.render(<PersonClass {...p1} />, document.getElementById("example"));
效果:

refs
-
组件内的标签都可以定义 ref 属性来标识自己,例如:
this.msgInput = input}/> -
在组件中可以通过
this.msgInput来得到对应的真实DOM元素 -
可通过 ref 获取组件内容特定标签对象,进行读取其相关数据
refs 使用的小案例
新建一个 click 事件,在点击按钮时弹出文本框中的内容:
<div id="example"></div><script type="text/babel">class MyComponent extends React.Component {constructor(props) {super(props);this.click = this.click.bind(this);}click(e) {//e.target 得到发生事件的DOM元素对象//alert(e.target);alert(this.refs.first.value);}render() {return (<div><input type="text" ref="first" /><button type="button" onClick={this.click}>按钮</button></div>)}}ReactDOM.render(<MyComponent />, document.getElementById("example"));
</script>
注意:
- 组件内置的方法中的 this 为组件对象
- 在组件类中自定义的方法中 this 为 null
- 强制绑定 this 通过函数对象的 bind()
- 箭头函数(ES6模块化编码时才能使用)
组件内的事件
通过元素的 onXXX 属性指定一个事件处理函数,例如:onClick={this.click},在组件中定义一个 click 函数。
事件函数的使用
//这种事件函数需要在组件构造当中进行绑定,例如 this.click = this.click.bind(this);
click(event) {//操作...
}//下列定义事件函数的方法不需在构造中 bind()
click2 = (event) => {//操作...
}
//如果子组件要调用父组件函数的话,父组件需要将函数传给自组件,例如:
//这是父组件的 operate() 与 render() 函数
operate = (`可以定义参数,也可以空着`) => {//操作...
}render() {return (<div><Son operate={this.operate} /></div>)
}//子组件在调用父组件的函数前,需要规定参数类型,例如:
static propTypes = {operate: PropTypes.func.isRequired
}//子组件调用父组件函数
click = () => {//从props中获取事件函数const {operate} = this.props;operate(`定义了参数就传入参数`);
}render() {return (<div><a onClick={this.click}>操作</a></div>)
}
组件的生命周期
-
组件对象从创建到死亡它会经历特定的生命周期阶段
-
React组件对象包含一系列的勾子函数(生命周期回调函数),在生命周期特定时刻回调
-
在定义组件时可以重写特定的生命周期回调函数,让不同的函数做特定的工作
组件三个生命周期状态
-
Mount:将组件插入真实 DOM
-
Update:组件被重新渲染
-
Unmount:组件被移出真实 DOM
生命周期方法与流程
- 第一次初始化渲染显示:
ReactDOM.render()
-
constructor(): 创建对象初始化构造器,初始化 state -
componentWillMount(): 组件将被插入 DOM 时触发 -
render(): 组件插入虚拟 DOM 时触发,也就是开始渲染 -
componentDidMount(): 组件已经插入到 DOM 后触发
- 每次更新状态时
state: this.setSate()
-
componentWillUpdate(): 组件在更新数据前触发 -
render(): 更新(重新渲染) -
componentDidUpdate(): 组件更新后触发
- 移除组件:
ReactDOM.unmountComponentAtNode(containerDom)
componentWillUnmount(): 组件将要从 DOM 中移除触发
重要的生命周期方法
-
render(): 初始化渲染或更新渲染触发 -
componentDidMount(): 开启监听, 发送 ajax 请求 -
componentWillUnmount(): 做一些收尾工作, 如: 清理定时器 -
componentWillReceiveProps():
虚拟DOM 与 DOM Diff 算法
虚拟 DOM 指 JS 对象,也就是一个组件中 render() 方法中的 html 元素,通过ReactDOM.render()方法将虚拟 DOM 转化为真实的 DOM
DOM Diff 算法:
- 当页面初始化完成,所有组件都渲染好之后
- 在后续操作中,某一个组件的 state 被改变
- React 重新创建虚拟 DOM 树
- React 比较旧 DOM 与 新 DOM 的区别
- 如果有区别,则重新渲染该组件,也就是重新调用 render() 方法
React Ajax
说明
-
React 本身只关注于界面, 并不包含发送 Ajax 请求的代码
-
前端应用需要通过 Ajax 请求与后台进行交互(json数据)
-
React 应用中需要集成第三方 Ajax 库(或自己封装)
常用的 Ajax 请求库
-
jQuery: 比较重,如果需要另外引入不建议使用
-
axios: 轻量级,建议使用
-
封装 XmlHttpRequest 对象的 Ajax
-
promise 风格
-
可以用在浏览器端和 node 服务器端
- fetch: 原生函数,但老版本浏览器不支持
-
不再使用 XmlHttpRequest 对象提交 Ajax 请求
-
为了兼容低版本的浏览器,可以引入兼容库 fetch.js
在 Reate 中使用 Ajax
这里使用 axios 来获取远程数据
- 引入 axios
- 在 React 中使用
componentDidMount() {const url = "localhost:8080/api/item";axios.get(url).then(response => {const { name, age } = response.data.items;this.setState({ name: name, age: age });}).catch(error => {//异常获取console.log(error.message);});
}
Fetch
Fetch 是 React 原生的异步请求工具,使用:
componentDidMount() {const url = "localhost:8080/api/item";//默认是 get 请求fetch(url).then(response => {return response.json();}).then(data => {const { full_name, html_url } = data.items[0];this.setState({ repoName: full_name, repoUrl: html_url });}).catch(error => {//异常获取console.log(error.message);});
}
Fetch 的 get 请求:
fetch(url).then(response => {return response.json();
}).then(data => {console.log(data)
}).catch(e => {console.log(e)
});
Fetch 的 post 请求:
fetch(url, {method: "POST",//要发送的数据body: JSON.stringify(data),
}).then(data => {console.log(data)
}).catch(e => {console.log(e)
});
组件间的通信
- 组件间常用的通信可以使用 props,例如上文那样传递数值或方法;但 props 传递只能一层一层传递,比如组件C要调用组件A的方法,而A中渲染B,B中再渲染C,方法就只能从 A->B->C 。
- 使用消息订阅(subscribe)、发布(publish)机制
- redux,后续说明
消息订阅发布机制
发布(publish)消息就像是去调用其他组件内的方法,将参数主动传递过去,而订阅(subscribe)像是定义了一个方法,等待别人来调用我。
使用
-
需要使用到 PubSubJS 库,在项目下
npm install pubsub-js --save安装 -
在项目中引入
import PubSub from 'pubsub-js' -
发布消息:
//public('方法名',参数);
PubSub.public('search', searchName);
- 订阅消息:
//subscribe('方法名',回调函数);
PubSub.subscribe('search', (msg, searchName) => {console.log(msg);//操作...
});
React-router
介绍
React-router 就是 React 路由组件,是一个专门的插件库,带有自己的组件标签;专门用来实现一个 SPA 应用
SPA 应用的理解
-
(single page web application)单页的 web 应用,React 中是组件套组件的开发方式,例如点击 nav 导航栏的链接,在浏览器中看似是在跳页面,其实只是改变了组件,页面并没有改变。
-
一个应用只有一个完整页面
-
点击页面按钮或链接不会刷新页面,当然也不会向服务器发请求
-
点击链接渲染另一个组件,做页面的局部刷新
-
数据都通过 Ajax 异步获取
对路由的理解
路由是什么?
一个路由就是一个键值对映射关系,key 就好比是对应组件的 url,value 就是即将渲染的组件名
路由分类(前台路由、后台路由)
前台路由例如:,当浏览器的 hash 变为 #myComponent 时, 当前路由组件就会变为 MyComponent 组件
后台路由例如:router.get(path, function(req, res)),当 node 接收到一个请求时,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据
前台路由实现
- history库
-
网址: https://github.com/ReactTraining/history
-
管理浏览器会话历史(history)的工具库
-
包装的是原生 DOM 中 window.history 和 window.location.hash 对象
- history API
-
History.createBrowserHistory(): 得到封装 window.history 的管理对象
-
History.createHashHistory(): 得到封装 window.location.hash 的管理对象
-
history.push(): 添加一个新的历史记录
-
history.replace(): 用一个新的历史记录替换当前的记录
-
history.goBack(): 回退到上一个历史记录
-
history.goForword(): 前进到下一个历史记录
-
history.listen(function(location){}): 监视历史记录的变化
React-router 相关 API
组件
路由基本使用
先安装 router 组件:在项目目录命令行下npm install --save react-router
引入组件:import {NavLink} from 'react-router-dom'
在项目入口处的 index.js 中要引用:
import React from 'react'
import { render } from 'react-dom'
import { BrowserRouter } from 'react-router-dom'
import App from './components/App'render(<BrowserRouter><App /></BrowserRouter>, document.getElementById("root")
);
组件是一个基本的导航链接组件,使用例如:
<div className="list-group"><NavLink className="list-group-item" to='/about' >About</NavLink><NavLink className="list-group-item" to='/home'>Home</NavLink>
</div>
下面是前台路由组件:
<div className="panel-body"><Switch><Route path='/about' component={About} /><Route path='/home' component={Home} /><Redirect to='/about' /></Switch>
</div>
的 to 属性与的 path 属性一致,component 属性对应要渲染的控件。


嵌套路由的使用
嵌套路由就是在一级路由下的组件中,再定义其他路由。在上文的案例中的 Home 组件中再定义路由:
export default function Home() {return (<div><h2>Home组件内容</h2><div><ul className='nav nav-tabs'><li><NavLink to='/home/news'>News</NavLink></li><li><NavLink to='/home/message'>Messages</NavLink></li></ul></div><div className="panel-body"><Switch><Route path='/home/news' component={News} /><Route path='/home/message' component={Messages} /><Redirect to='/home/news' /></Switch></div></div>)
}
组件相当于默认的路由,当 Home 组件渲染完成时,自动渲染 News 组件。


向路由组件中传递参数
延续上文案例,Messages 组件中包含三个链接,点击其中一个链接并传入不同 id,在 Messages 组件的下方显示对应 id 的信息,先看看 Messages 组件:
import React, { Component } from 'react'
import { Route, NavLink } from 'react-router-dom'
import Message_detai from './Message_detai'export default class Mssages extends Component {state = { messages: [] }componentDidMount() {let messages = [{ id: 1, title: 'message001' },{ id: 3, title: 'message003' },{ id: 5, title: 'message005' },];this.setState({ messages });}render() {return (<div><ul>{this.state.messages.map((element, index) => {return <li key={index}><NavLink to={`/home/message/messagedetail/${element.id}`}>{element.title}</NavLink></li>})}</ul><Route path='/home/message/messagedetail/:id' component={Message_detai} /></div>)}
}
将 messages 数组中的 id 的赋予链接,中使用 :id 表示所传的参数,格式也就是:参数名。再看 Message_detai:
import React from 'react'const messageDetails = [{ id: 1, title: 'Message001', content: 'content1' },{ id: 2, title: 'Message002', content: 'content2' },{ id: 3, title: 'Message003', content: 'content3' },
]export default function Message_detai(props) {const { id } = props.match.params;const msg = messageDetails.find((msg) => msg.id === id * 1);return (<ul><li>id:{msg.id}</li><li>title:{msg.title}</li><li>content:{msg.content}</li></ul>)
}
const { id } = props.match.params;是从 props 中获取名为 id 的参数,messageDetails.find( function(){} )是遍历数组,直到方法返回 true 时返回此刻遍历到的对象,(msg) => msg.id === id * 1,msg 就是数组中的对象,当两个 id 相等时返回 true,因为从 props 中获取的 id 值类型是字符串,所有要*1变成数字。

Redux
Redux 是什么
-
redux是一个独立专门用于做状态管理的JS库(不属于 react 插件库)
-
它可以用在 react, angular, vue 等项目中, 但基本与 react 配合使用
-
作用:集中式管理 react 应用中多个组件共享的状态(变量),可以说 redux 就是将多个组件共享的变量封装到一个 js 中,对变量增删改查的方法也封装到 js 中,解决组件间各种传参而导致关系复杂冗余的问题
Redux 工作流程

先了解 redux的三个核心概念:action、store、reducer
- reducer 中封装了对变量的操作方法,传入方法的参数为 state 与 action,state 不是react 中的状态,只是一个变量;action 是一个对象,表明要对 state 做什么操作;使用例如:
//对 state 进行增减的方法
// state = 0 表明state的初始值为0
export function count(state = 0, action) {switch (action.type) {case 'add':return state + action.data;case 'cut':return state - action.data;default:return state;}
}
- action 就是传入 reducer 方法中的对象,包含 type、data 属性,type 值为字符串,类似于方法名,具有唯一性,data 就是数据,值类型任意;type 为必要参数,data 为可选参数。使用例如:
//增加
export const INCREMENT = (number) => ({ type: 'add', data: number })
//减少
export const DECREMENT = (number) => ({ type: 'cut', data: number })
- store 是将 state,action,reducer 联系在一起的对象。react 组件调用
store.getState()获取 state 值,调用store.dispatch(action对象)方法去修改 state,调用store.subscribe(渲染组件)去重新渲染组件。使用例如:
this.props.store.dispatch(actions.INCREMENT(count));
工作流程:
react 组件首先要拿到一个 action 对象,可以在一个 js 中定义很多 action 对象,再去获取 store 对象,store 对象可由父组件通过 props 传给子组件,调用 store 的 dispatch 方法传入 action,然后进入 reducer 的方法中,reducer 判断 action 的 type ,对 state 进行操作,返回一个新得 state 给 store,state 一旦改变,则会触发 store 的 subscribe 方法。
什么情况下需要使用 redux
-
总体原则: 能不用就不用,如果不用比较吃力才考虑使用
-
某个组件的状态,需要共享
-
某个状态需要在任何地方都可以拿到
-
一个组件需要改变全局状态
-
一个组件需要改变另一个组件的状态
对 state 进行增减的案例代码:
npm install --save redux安装 redux
项目结构:

先创建 store.js :
//store.js
import { counter } from './reducers'
import { createStore } from 'redux'//创建一个 store 对象,传入 reducer 中的方法
const store = createStore(counter);export default store
inedx.js :
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App';
import store from './redux/store'function render() {ReactDOM.render(<App store={store} />, document.getElementById('root'));
}//初始化渲染
render();//订阅监听,store中状态变化触发该函数
store.subscribe(render);
actios.js :
//存放 action 对象的 js
import { increment, decrement } from './action_types'
//增加
export const INCREMENT = (number) => ({ type: increment, data: number })
//减少
export const DECREMENT = (number) => ({ type: decrement, data: number })
action_types.js :
//action 对象的type类型
export const increment = 'increment'
export const decrement = 'decrement'
reducers.js :
/*** 包含n个reducer的模块*/
import { increment, decrement } from './action_types'export function counter(state = 0, action) {switch (action.type) {case increment:return state + action.data;case decrement:return state - action.data;default:return state;}
}
主组件 App.jsx :
import React from 'react'
import * as actions from '../redux/actions'export default class App extends React.Component {add = () => {const count = this.select.value * 1;this.props.store.dispatch(actions.INCREMENT(count));}cut = () => {const count = this.select.value * 1;this.props.store.dispatch(actions.DECREMENT(count));}addIfOdd = () => {if (this.props.store.getState() % 2 === 1) {const count = this.select.value * 1;this.props.store.dispatch(actions.INCREMENT(count));}}render() {const count = this.props.store.getState();return (<div><p>click {count} times</p><div><select ref={select => this.select = select}><option>1</option><option>2</option><option>3</option></select> <button onClick={this.add}>+</button> <button onClick={this.cut}>-</button> <button onClick={this.addIfOdd}>add if 奇数</button> </div></div>)}
}
react-redux
之前的 react 组件中还存在着 redux 代码,可使用 react-redux 插件将所有组件分为制作 UI 的组件类与管理数据和业务的 redux 类。
- UI组件
-
只负责 UI 的呈现,不带有任何业务逻辑
-
通过 props 接收数据(一般数据和函数)
-
不使用任何 Redux 的 API
-
一般保存在 components 文件夹下
- 容器组件
-
负责管理数据和业务逻辑,不负责UI的呈现
-
使用 Redux 的 API
-
一般保存在 containers 文件夹下
将之前的对 state 操作的代码进行修改
首先安装npm install --save react-redux
将 App.jsx 中的 redux 代码整合到另一个 js 中,将 App.jsx 更名为 Counter.jsx:
/*
UI组件: 不包含任何redux API*/
import React from 'react'
import PropTypes from 'prop-types'export default class Counter extends React.Component {//使用 props 接受参数static propTypes = {count: PropTypes.number.isRequired,increment: PropTypes.func.isRequired,decrement: PropTypes.func.isRequired}add = () => {const count = this.select.value * 1;this.props.increment(count);}cut = () => {const count = this.select.value * 1;this.props.decrement(count);}addIfOdd = () => {if (this.props.count % 2 === 1) {const count = this.select.value * 1;this.props.increment(count);}}render() {const { count } = this.props;return (<div><p>click {count} times</p><div><select ref={select => this.select = select}><option>1</option><option>2</option><option>3</option></select> <button onClick={this.add}>+</button> <button onClick={this.cut}>-</button> <button onClick={this.addIfOdd}>add if 奇数</button> </div></div>)}
}
当然被抽取出来的 redux 代码给 Counter.jsx 传值,其被封装为 App.js:
import React from 'react'
import { connect } from 'react-redux'
import { INCREMENT, DECREMENT } from '../redux/actions'
import Counter from '../components/Counter'//将redux与react联系起来,为props属性赋值
//该方法用于包装 UI 组件生成容器组件,将参数赋予 Counter
export default connect(state => ({ count: state }),{ increment: INCREMENT, decrement: DECREMENT }
)(Counter)
index.js 中 :
import React from 'react';
import ReactDOM from 'react-dom';
import App from './container/App';
import store from './redux/store'
import { Provider } from 'react-redux'ReactDOM.render(//Provider让所有组件都可以得到state数据,并维护store<Provider store={store}><App /></Provider>, document.getElementById('root')
);
代码结构:

最早 react 组件是获取 action 对象,再获取 store 对象,拿 store 去调用方法,现在优化后组件与 redux 隔离开来,直接调用从外部传来的方法。connect 将 store 与组件连接在一起。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
