[Full-stack] 快速上手开发 - React
故事背景
[1] 博客笔记结合《React快速上手开发》再次系统地、全面地走一遍。
[2] React JS Tutorials:包含了JS --> React --> Redux --> Mobx
项目部署
着眼于ful-stack全局,了解前后端的部署,之后才能深刻理解react的角色与位置。
1. 服务器部署
[AWS] Deploy react project on EC2
2. 用户权限管理
3. 这就是未来后端的趋势
React基本路线
一、静态的html变为了动态生成
- React自己的html表达方式
<script>
ReactDOM.render(
React.DOM.h1(
{id: "my-heading"},
React.DOM.span(null,
React.DOM.em(null, "Hell"),
"o"
),
" world!"
),
document.getElementById('app')
);
</script>
- 命名冲突:class, for, style
<script>
ReactDOM.render(
/*
// COUNTEREXAMPLE
// this doesn't work
React.DOM.h1(
{
class: "pretty",
for : "me",
},
"Hello world!"
),
*/ // PROPER EXAMPLE
// this works
React.DOM.h1(
{
className: "pretty",
htmlFor : "me",
},
"Hello world!"
), document.getElementById('app')
);
</script>
style倒是经常用到。
<script>
ReactDOM.render(
/*
// COUNTEREXAMPLE
// this doesn't work
React.DOM.h1(
{
style: "background: black; color: white; font-family: Verdana",
},
"Hello world!"
),
*/ // PROPER EXAMPLE
// this works
React.DOM.h1(
{
style: {
background: "black",
color: "white",
fontFamily: "Verdana",
}
},
"Hello world!"
), document.getElementById('app')
);
</script>
思考:可见以上的写法,可读性比较差,这也是之后引入JSX的重要原因。
下图中上面的JSX写法就接近了原始的HTML格式,看起来更更为习惯。
Goto for more details: [React] 01 - Intro: javaScript library for building user interfaces - React JSX
二、自定义组件才是React的威力
- 对React.DOM做了封装
<script>
var Component = React.createClass({
render: function() {
return React.DOM.span(null, "I'm so custom");
}
});
ReactDOM.render(
React.createElement(Component), // 这里之前是React.DOM代码,现在封装了起来
document.getElementById("app")
);
</script>
附加题:React 工厂方法——createFactory使用详解【为何感觉用处不是很大】
- props - 获取属性
<script>
var Component = React.createClass({
/**
* 可以采用PropTypes检查props
*/ /**
* 如果没有name属性,会报错,
* 可以设置一个默认的
*/
render: function() {
return React.DOM.span(null, "My name is " + this.props.name);
}
});
ReactDOM.render(
React.createElement(Component, {
name: "Bob",
}), <Component name="Bob" /> // <---- 看来JSX的写法更为舒服,createElement看着别扭!
document.getElementById("app")
);
</script>
附加题:react demo10 (设置组件属性的默认值getDefaultProps)
复合组件:Composite Component 表示 创建多个组件来合成一个组件,把组件的不同功能点进行分离。Goto for more details: [React] 01 - Intro: javaScript library for building user interfaces - 复合组件,React Props
子节点的获取:[React] 01 - Intro: javaScript library for building user interfaces - this.props.children
- state - 通过状态改变设置属性
<script>
var TextAreaCounter = React.createClass({
propTypes: {
text: React.PropTypes.string,
},
getDefaultProps: function() {
return {
text: '',
};
},
getInitialState: function() {
return {
text: this.props.text,
};
},
_textChange: function(ev) {
this.setState({ // Jeff: setState 触发界面更新,因为这里把prop变了
text: ev.target.value, // event.target:使用合成事件来消除浏览器之间的不一致情况
});
},
render: function() {
return React.DOM.div(null,
React.DOM.textarea({
value : this.state.text,
onChange: this._textChange,
}),
React.DOM.h3(null, this.state.text.length)
);
}
});
ReactDOM.render(
React.createElement(TextAreaCounter, {
text: "Bob", // 这里其实是个初始值,所以命名为defaultValue会好些
}),
document.getElementById("app")
);
</script>
附加题:事件处理,书p20。
React 组件 API,除了setState,还有其他6种方法:
- 设置状态:setState
- 替换状态:replaceState
- 设置属性:setProps
- 替换属性:replaceProps
- 强制更新:forceUpdate
- 获取DOM节点:findDOMNode
- 判断组件挂载状态:isMounted
- 从外部访问组件
如何定义”外部“?通过 myTextAreaCounter 设置新的state值 as following。
myTextAreaCounter.setState({text: "Hello outside world!" });
以下定义了myTextAreaCounter。
<script>
var TextAreaCounter = React.createClass({
propTypes: {
defaultValue: React.PropTypes.string,
},
getInitialState: function() {
return {
text: this.props.defaultValue,
};
},
_textChange: function(ev) {
this.setState({
text: ev.target.value,
});
},
render: function() {
return React.DOM.div(null,
React.DOM.textarea({ // text --> input
value : this.state.text,
onChange: this._textChange,
}),
React.DOM.h3(null, this.state.text.length)
);
}
}); ---------------------------------------------------------
var myTextAreaCounter = ReactDOM.render(
React.createElement(TextAreaCounter, {
defaultValue: "Bob",
}),
document.getElementById("app")
);
</script>
附加题:组件也算是代码"分离思想"的一种体现,参看笔记:[React] 08 - Tutorial: evolution of code-behind【from HTML静态页面 to 复合组件】
- 组件间的传值
参见笔记 [React] 09 - Tutorial: components
(11) 子组件向父组件传值 - 子组件调用父组件的“方法”,以”函数指针“的类似形式;
(12) 子组件之间的传值
(13) 双向数据绑定
[Redux]
通过这件事,让我们明白了Redux的重要性。
Goto for more details: [React] 02 - Intro: why react and its design pattern - 背后的思想:一步一步进化到 Redux
以及相关笔记:
- [React] 11 - Redux: redux
- [React] 12 - Redux: async & middleware
- [React] 13 - Redux: react-redux
- [React] 14 - Redux: Redux Saga
- [React] 15 - Redux: TodoMVC
- [看漫画,学 Redux] —— A cartoon intro to Redux
- 如何评价数据流管理架构 Redux? - 杨森
有必要另起一文走一遍!
三、组件的生命周期
- 组件的创建
Ref: React创建组件的三种方式及其区别
- 函数式定义的
无状态组件 - es5原生方式
React.createClass定义的组件 【`React.createClass`是react刚开始推荐的创建组件的方式,这是ES5的原生的JavaScript来实现的React组件】 - es6形式的
extends React.Component定义的组件
- 函数式定义的
随着React的发展,React.createClass形式自身的问题暴露出来:
- React.createClass 会自绑定函数方法(不像React.Component只绑定需要关心的函数)导致不必要的性能开销,增加代码过时的可能性。
- React.createClass 的mixins不够自然、直观;
- React.Component 形式非常适合高阶组件(Higher Order Components -- HOC),它以更直观的形式展示了比mixins更强大的功能,并且HOC是纯净的JavaScript,不用担心他们会被废弃。
- HOC 可以参考 无状态组件(Stateless Component) 与高阶组件。
- mixins将死,ES6的Class不对其进行支持,HOC就是解决办法。
(1) 当前老旧写法:
var InputControlES5 = React.createClass({
propTypes: {//定义传入props中的属性各种类型
initialValue: React.PropTypes.string
},
defaultProps: { //组件默认的props对象
initialValue: ''
},
// 设置 initial state
getInitialState: function() {//组件相关的状态对象
return {
text: this.props.initialValue || 'placeholder'
};
},
handleChange: function(event) {
this.setState({ //this represents react component instance
text: event.target.value
});
},
render: function() {
return (
<div>
Type something:
<input onChange={this.handleChange} value={this.state.text} />
</div>
);
}
});
--------以下没区别------------------------
InputControlES5.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES5.defaultProps = {
initialValue: ''
};
(2) 未来推崇写法:【其实就是使用了js6的类的新特性】
class InputControlES6 extends React.Component {
constructor(props) {
super(props);
// 设置 初始状态
this.state = {
text: props.initialValue || 'placeholder'
};
// ES6 类中函数必须手动绑定
this.handleChange = this.handleChange.bind(this); // React.Component创建的组件,其成员函数不会自动绑定this,需要开发者手动绑定,否则this不能获取当前组件实例对象。
}
handleChange(event) {
this.setState({
text: event.target.value
});
}
render() {
return (
<div>
Type something:
<input onChange={this.handleChange}
value={this.state.text} />
</div>
);
}
}
--------以下没区别------------------------
InputControlES6.propTypes = {
initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
initialValue: ''
};
Jeff:
但是,使用类的概念后,意思就自然而然地跟着变了:
作为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。
通过bind锁定this:
- 可以在构造函数中完成绑定,【以上例子】
- 也可以在调用时使用
method.bind(this)来完成绑定, - 还可以使用arrow function来绑定。
<div onClick={this.handleClick.bind(this)}></div> // 2.使用bind来绑定
<div onClick={()=>this.handleClick()}></div> // 3.使用arrow function来绑定
- 无状态组件
1、只要有可能,尽量使用无状态组件创建形式。
2、否则(如需要state、生命周期方法等),使用`React.Component`这种es6形式创建组件。
Ref: React中的无状态和有状态组件【原文看似不错】
无状态的函数写法,又称为纯组件SFC。它是一种只负责展示的纯组件。
对于这种无状态的组件,使用函数式的方式声明,会使得代码的可读性更好,并能大大减少代码量,箭头函数则是函数式写法的最佳搭档:
const Todo = (props) => (
<li
onClick={props.onClick}
style={{textDecoration: props.complete ? "line-through" : "none"}}
>
{props.text}
</li>
)
上面定义的 Todo 组件,输入输出数据完全由props决定,而且不会产生任何副作用。
对于props为 Object 类型时,我们还可以使用 ES6 的解构赋值:
const Todo = ({ onClick, complete, text, ...props }) => (
<li
onClick={onClick}
style={{textDecoration: complete ? "line-through" : "none"}}
{...props}
>
{props.text}
</li>
)
无状态组件一般会搭配高阶组件(简称:HOC)一起使用,高阶组件用来托管state,Redux 框架就是通过 store 管理数据源和所有状态,其中所有负责展示的组件都使用无状态函数式的写法。
这种模式被鼓励在大型项目中尽可能以简单的写法 来分割原本庞大的组件,而未来 React 也会面向这种无状态的组件进行一些专门的优化,比如避免无意义的检查或内存分配。所以建议大家尽可能在项目中使用无状态组件。
无状态组件内部其实是可以使用ref功能的,虽然不能通过this.refs访问到,但是可以通过将ref内容保存到无状态组件内部的一个本地变量中获取到。
Ref: React无状态组件——为可复用而生
如何利用react提供的jsx语法写好一个可复用的组件呢?---- 最常用的组件是“无状态组件”
所谓无状态,也可以叫做无生命周期,无state,组件是一个纯jsx类或者对象。
这个组件内部没有任何的生命周期和state状态,那么如果需要管理state状态,该怎么办呢?---- Redux
# 这里自定义了一个head主键,可以复用,因为head的各部分细节由参数控制。
export class Header extends Component {
render() {
const {title, imgUrl, linkTo, bgColor} = this.props
//提供4个接口参数给父容器做设置,可以不传参。
return (
<header className='header' style={bgColor}>
{title}
<Link to={linkTo} className="a_link" >
<img src={imgUrl} className="a_img" />
</Link>
</header>
)
}
//严格来说,这些暴露给外部的参数都需要做验证,常用的验证类型为array,bool,func,number,object,string
static propTypes = {
title: React.PropTypes.string.isRequired
}
}
附加题:Mixins的支持不同 ----> 走向"高阶组件"
For more details, go to: [React] 16 - Topic: Mixins & Higher-Order Components
React.Component这种形式并不支持Mixins,至今React团队还没有给出一个该形式下的官方解决方案;但是React开发者社区提供一个全新的方式来取代
Mixins,那就是 Higher-Order Components。所谓 HOC:会返回组件的组件,Redux就是一个实现例子,可处理状态。
由于React团队已经声明 React.createClass最终会被React.Component的类形式所取代。
但是在找到
Mixins替代方案之前是不会废弃掉React.createClass形式。所以:
"能用React.Component创建的组件的就尽量不用React.createClass形式创建组件"
- 三个状态,七个方法
参见笔记 [React] 09 - Tutorial: components,并结合raisl365系列 之 诱人的 react 视频教程-基础篇
【代码有必要详细研究与实践】
实验代码的基本思路是:
"点击按钮 ----> 改变某state ----> 触发render ----> 通过if判断语句,跳过某component的渲染 ----> 达到组件消失的效果“
路由: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# 静态路由配置的小助手
一、传统方式
[React] 05 - Route: connect with ExpressJS
[React] 06 - Route: koa makes your life easier
可见,路由的处理采用的是:在后端代码中采用类似switch的方式判断前端发来的URL request。
那么问题来了,react是前端的东西,react-router是前端还是后端?或者,是一个介于中间的东西?
答案是:前端路由!
二、React-router方式
参见:[React] 10 - Tutorial: router
Yuan Yifeng有整理:React Router 使用教程,在此补充些遗漏的内容。
Ref: 官方路由示范代码
- 嵌套路由 + hash
如此,不用使用关键字:exact
用户访问/repos时,
- 先加载
App组件, - 然后在它的内部再加载
Repos组件。
- 先加载
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="/repos" component={Repos}/>
<Route path="/about" component={About}/>
</Route>
</Router>
URL with hash value.
http://localhost:8080/#/about?_k=z86gvy
- props.children
export default React.createClass({
render() {
return (
<div>
<h1>React Router Tutorial</h1>
<ul role="nav">
<li><Link to="/about">About</Link></li>
<li><Link to="/repos">Repos</Link></li>
</ul>
{this.props.children}
</div>
)
}
})
Result:

- ... this.props
导入所有的参数并展开
<ul role="nav">
<li><NavLink to="/about">About</NavLink></li>
<li><NavLink to="/repos">Repos</NavLink></li>
</ul>
将Link 统一变为记录活动状态带有颜色的link。
render() {
return <Link {...this.props} activeClassName="active"/>
}
更多内容:
详见 [React] 10 - Tutorial: router - URL的参数处理
- 其他内容
十一、表单处理
十二、路由的钩子
Jeff: 以上便是react周边最为亲近的一些知识点
[Full-stack] 快速上手开发 - React的更多相关文章
- 【java框架】MyBatis-Plus(1)--MyBatis-Plus快速上手开发及核心功能体验
1.MyBatis-Plus入门开发及配置 1.1.MyBatis-Plus简介 MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变, ...
- 快速上手开发——JFinal配置(全步骤图文解析)
摘要: 因为发现官网上只有Eclipse的配置文档,就写了这篇基于IDEA+maven的配置流程.本文使用安装了maven插件的IDEA进行配置,为了照顾IDEA新手,几乎每个步骤都截了图. 环境说明 ...
- 官方 React 快速上手脚手架 create-react-app
此文简单讲解了官方 React 快速上手脚手架的安装与介绍. 1. React 快速上手脚手架 create-react-app 为了快速地进行构建使用 React 的项目,FaceBook 官方发布 ...
- Java开发快速上手
Java开发快速上手 前言 1.我的大学 2.对初学者的建议 3.大牛的三大特点 4.与他人的差距 第一章 了解Java开发语言 前言 基础常识 1.1 什么是Java 1.1.1 跨平台性 1.2 ...
- React:快速上手(7)——使用中间件实现异步操作
React:快速上手(7)——使用中间件实现异步操作 本文参考链接:Stack Overflow redux-thunk 我们使用store.dispath进行派发时,只能传递一个普通对象进去,如下: ...
- React:快速上手(4)——掌握Redux(1)
React:快速上手(4)——掌握Redux 引入Redux 混乱的state管理 随着 JavaScript 单页应用开发日趋复杂,JavaScript 需要管理比任何时候都要多的 state (状 ...
- React:快速上手(1)——基础知识
React:快速上手(1)——基础知识 React(有时叫React.js或ReactJS)是一个为数据提供渲染为HTML视图的开源JavaScript库,用于构建用户界面. JSX.元素及渲染 1. ...
- React:快速上手(8)——前后端分离的跨域访问与会话保持
React:快速上手(8)——前后端分离的跨域访问与会话保持 跨域访问 跨域是指从一个域名的网页去请求另一个域名的资源.比如从http://www.baidu.com/ 页面去请求http://www ...
- 前端开发工具包 WijmoJS 2019V1正式发布:全新的在线 Demo 系统,助您快速上手,开发无忧
前端开发工具包WijmoJS在2019年的第一个主要版本2019V1已经发布,本次发布包括了更加易用的在线Demo系统.各控件新增功能.NPM 包的改动,以及全新的浏览器API组件. WijmoJ ...
随机推荐
- CocosCreator资源工作流程
--摘自官方文档 资源工作流程 添加资源 资源管理器 提供了三种在项目中添加资源的方式: 通过 创建按钮 添加资源 在操作系统的文件管理器中,将资源文件复制到项目资源文件夹下,之后再打开或激活 Coc ...
- 服务器被ddos攻击?分析如何防止DDOS攻击?
上周知名博主阮一峰的博客被DDOS攻击,导致网站无法访问而被迫迁移服务器的事情,引起了广大网友的关注及愤慨,包括小编的个人博客也曾接受过DDOS的“洗礼”,对此感同身受.所以,本文我们一起来了解下DD ...
- 广州移动宽带DNS
目前还搞不明白这些DNS服务器是怎么得出来的,现在只停留在网上收集. 下面是收集比较靠谱的DNS广州移动宽带的: ns3.gd.cnmobile.net 221.179.38.7 ns4.gd.cnm ...
- 【荐】详解 golang 中的 interface 和 nil
golang 的 nil 在概念上和其它语言的 null.None.nil.NULL一样,都指代零值或空值.nil 是预先说明的标识符,也即通常意义上的关键字.在 golang 中,nil 只能赋值给 ...
- 内置系统账户:Local system/Network service/Local Service 区别
参考文献: http://www.cnblogs.com/xianspace/archive/2009/04/05/1429835.html 前言 今天在安装sqlserver2008 r2的时候,在 ...
- C#利用QRCoder生产二维码
系统使用.NET4.5.1 代码如下: using System; using System.Collections.Generic; using System.Linq; using System. ...
- iOS:百度长语音识别具体的封装:识别、播放、进度刷新
一.介绍 以前做过讯飞语音识别,比较简单,识别率很不错,但是它的识别时间是有限制的,最多60秒.可是有的时候我们需要更长的识别时间,例如朗诵古诗等功能.当然讯飞语音也是可以通过曲线救国来实现,就是每达 ...
- scala recursive value x$5 needs type
recursive value x$5 needs type的原因是使用了一个类型不确定的变量,例如 val (id, name) = (id, getName(id)) 其中id是个变量,其值还不确 ...
- 一文看懂 Dubbo 的集成与使用
前言 今年年初时,阿里巴巴开源的高性能服务框架dubbo又开始了新一轮的更新,还加入了Apache孵化器.原先项目使用了spring cloud之后,已经比较少用dubbo.目前又抽调回原来的行业应用 ...
- HTML解析库Gumbo简单使用记录
目录 Gumbo简介 使用记录 1.GumboNode的类型 2.简单的使用 Gumbo简介 Gumbo是谷歌开源的一个纯C编写的HTML解析库,性能很好,就是用起来比较麻烦. github地址htt ...
