[Full-stack] 快速上手开发 - React

故事背景


[1] 博客笔记结合《React快速上手开发》再次系统地、全面地走一遍。html

[2] React JS Tutorials:包含了JS --> React --> Redux --> Mobx 前端

 

 

项目部署


着眼于ful-stack全局,了解先后端的部署,以后才能深入理解react的角色与位置。java

1. 服务器部署react

[AWS] Deploy react project on EC2git

2. 用户权限管理es6

[AWS] OAuth2.0github

[AWS] User managementweb

[AWS] Amazon Cognitoredux

3. 这就是将来后端的趋势后端

[AWS] Serverless

 

 

React基本路线


1、静态的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

 

 

2、自定义组件才是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

以及相关笔记: 

有必要另起一文走一遍!

 

 

3、组件的生命周期

  • 组件的建立

Ref: React建立组件的三种方式及其区别

    1. 函数式定义的无状态组件
    2. es5原生方式React.createClass定义的组件  【`React.createClass`是react刚开始推荐的建立组件的方式,这是ES5的原生的JavaScript来实现的React组件】
    3. 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);  // 建立的组件,其成员函数不会自动绑定this,须要开发者手动绑定,不然this不能获取当前组件实例对象。  } handleChange(event) { this.setState({ text: event.target.value }); } render() { return ( <div> Type something: <input onChange={this.handleChange} value={this.state.text} /> </div> ); } }

React.Component
--------如下没区别------------------------

InputControlES6.propTypes = {
    initialValue: React.PropTypes.string
};
InputControlES6.defaultProps = {
    initialValue: ''
};

Jeff:
可是,使用类的概念后,意思就天然而然地跟着变了:
做为组件类的属性,不是组件实例的属性,也就是所谓的类的静态属性来配置的。

 

经过bind锁定this:

  1. 能够在构造函数中完成绑定,【以上例子】
  2. 也能够在调用时使用method.bind(this)来完成绑定,
  3. 还可使用arrow function来绑定。
<div onClick={this.handleClick.bind(this)}></div>    // 2.使用bind来绑定
<div onClick={()=>this.handleClick()}></div> // 3.使用arrow function来绑定

 

  • 无状态组件

一、只要有可能,尽可能使用无状态组件建立形式。

二、不然(如须要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 Router
  • react-router-native       # 用于 React Native 的 React Router
  • react-router-redux         # React Router 和 Redux 的集成
  • react-router-config       # 静态路由配置的小助手

 

1、传统方式

[React] 05 - Route: connect with ExpressJS

[React] 06 - Route: koa makes your life easier

可见,路由的处理采用的是:在后端代码中采用相似switch的方式判断前端发来的URL request。

那么问题来了,react是前端的东西,react-router是前端仍是后端?或者,是一个介于中间的东西?

答案是:前端路由!

 

 

2、React-router方式

参见:[React] 10 - Tutorial: router

Yuan Yifeng有整理:React Router 使用教程,在此补充些遗漏的内容。

Ref: 官方路由示范代码

 

  • 嵌套路由 + hash

如此,不用使用关键字:exact

用户访问/repos时,

    1. 先加载App组件,
    2. 而后在它的内部再加载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的参数处理 

 

  • 其余内容

11、表单处理

12、路由的钩子

 

 

Jeff: 以上即是react周边最为亲近的一些知识点

相关文章
相关标签/搜索