写给PHP程序猿的React知识(上)-大前端从菜鸟到大神进阶路线图系列

写给PHP程序猿的React知识(上)-大前端从菜鸟到大神进阶路线图系列

最近公司在搞全栈开发,要求后端程序猿也要写前端代码,框架用的是React。作为后端程序猿,大家多多少少还是接触过一些前端知识的,基本的javascript还是会写的,但还是会有以下疑问:

  1. ES6的特性那么多,我需要全部学会吗?
  2. React Component有3种写法,我需要都学习吗?
  3. JSX是啥?
  4. React的路由怎么配置?
  5. 如何请求后端的接口数据?
  6. 组件间如何传递数据?
  7. HOOK是啥?useState和useEffect怎么用?

本文就是梳理了基于仅掌握基本javascript知识的后端程序猿使用React开发项目需要学习的最小知识集。

那些你要掌握的Javascript知识点

const 和 let

不要用 var,而是用 const 和 let,分别表示常量和变量。不同于 var 的函数作用域,const 和 let 都是块级作用域。

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

==上面代码中,变量i是var声明的,在全局范围内都有效。所以每一次循环,新的i值都会覆盖旧值,导致最后输出的是最后一轮的i的值。==

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6

==上面代码中,变量i是let声明的,当前的i只在本轮循环有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是6。==

变量的解构赋值

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)

// 以前,为变量赋值,只能直接指定值。
var a = 1;
var b = 2;
var c = 3;
//ES6允许这样写
var [a, b, c] = [1, 2, 3];
//解构不仅可以用于数组,还可以用于对象。
var { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
模板字符串

传统的JavaScript语言,输出模板通常是这样写的。

var product = {name:'',price:120,image:'http:/product.png'};
$('body').append(
  '<div><img src="' + product.image + '/></div>' +
  '<p>' + product.name + '</p>'+
  '<p>' + product.price + '</p>'
);

上面这种写法相当繁琐不方便,ES6引入了模板字符串解决这个问题。

var product = {name:'',price:120,image:'http:/product.png'};
$('body').append(`<div><img src="${product.image}" /></div>
  <p>${product.name}</p>
  <p>${product.price}</p>
`);

==模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。==

模块化

ES5不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,通过import来引用其它模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。

  • export
//abc.js

//导出变量
export var name = '我是变量';
//导出常量
export const C_NAME = '我是常量';
//导出函数
export function add(x,y){
    return x + y;
}
//导出多个变量
var a = 'Hello';
var b = 'World';
export {a,b};
import {a,b} from 'abc.js';
import {add} from 'abc.js';
import {name} from 'abc.js';

==export default 命令==

从前面的例子可以看出,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。

为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。

// export-default.js
export default function () {
  console.log('foo');
}

上面代码是一个模块文件export-default.js,它的默认输出是一个函数。

其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。

// import-default.js
import customName from './export-default';
customName(); // 'foo'
箭头函数

这是ES6中最令人激动的特性之一。=>不只是关键字function的简写,它还带来了其它好处。箭头函数与包围它的代码共享同一个this,能帮你很好的解决this的指向问题。有经验的JavaScript开发者都熟悉诸如var self = this;或var that = this这种引用外围this的模式。但借助=>,就不需要这种模式了。

箭头函数的箭头=>之前是一个空括号、单个的参数名、或用括号括起的多个参数名,而箭头之后可以是一个表达式(作为函数的返回值),或者是用花括号括起的函数体(需要自行通过return来返回值,否则返回的是undefined)。

// 箭头函数的例子
// 无参数
()=>1
//一个参数,直接返回表达式
v=>v+1
//多个参数,直接返回表达式
(a,b)=>a+b
//函数体
()=>{
    alert("foo");
}
//函数体
e=>{
    if (e == 0){
        return 0;
    }
    return 1000/e;
}

==坑点:不论是箭头函数还是bind,每次被执行都返回的是一个新的函数引用,因此如果你还需要函数的引用去做一些别的事情(譬如卸载监听器),那么你必须自己保存这个引用。==

// 错误的写法
class PauseMenu extends React.Component{
    componentWillMount(){
        AppStateIOS.addEventListener('change', this.onAppPaused.bind(this));
    }
    componentWillUnmount(){
        AppStateIOS.removeEventListener('change', this.onAppPaused.bind(this));
    }
    onAppPaused(event){
    }
}
//正确的写法
class PauseMenu extends React.Component{
    componentWillMount(){
        AppStateIOS.addEventListener('change', this.onAppPaused);
    }
    componentWillUnmount(){
        AppStateIOS.removeEventListener('change', this.onAppPaused);
    }
    onAppPaused = (event) => {
        //把函数直接作为一个arrow function的属性来定义,初始化的时候就绑定好了this指针
    }
}
延展操作符(Spread operator)

延展操作符 ==...== 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造对象时, 将对象表达式按key-value的方式展开。

function sum(x, y, z) {
  return x + y + z;
}
const numbers = [1, 2, 3];

//不使用延展操作符
console.log(sum.apply(null, numbers));

//使用延展操作符
console.log(sum(...numbers));// 6
const stuendts = ['Jine','Tom']; 
const persons = ['Tony',... stuendts,'Aaron','Anna'];
conslog.log(persions)// ["Tony", "Jine", "Tom", "Aaron", "Anna"]
//在React中的应用
var params = {
    name: '123',
    title: '456',
    type: 'aaa'
}

var { type, ...other } = params;

<CustomComponent type='normal' number={2} {...other} />
//等同于
<CustomComponent type='normal' number={2} name='123' title='456' />

React Component

React Component 有 3 种定义方式,分别是 React.createClass, class 和 Stateless Functional Component。推荐尽量使用最后一种,保持简洁和无状态。这是函数,不是 Object,没有 this 作用域,是 pure function。

export default Menu = (props)=>{
    handleClick() {
        props.dispatch({ type: 'app/create' })
    }

    return (
        <div onClick={handleClick}>{props.name}</div>
    )
}

等同于

export default class Menu extends React.Component {
    handleClick() {
        this.props.dispatch({ type: 'app/create' });
    }

    render() {
        return <div onClick={this.handleClick.bind(this)}>{this.props.name}</div>
    }
}

JSX

const element = <h1>Hello, world!</h1>;

这个有趣的标签语法既不是字符串也不是 HTML。

它被称为 JSX,是一个 JavaScript 的语法扩展,具有 JavaScript 的全部功能。

const customMethod = ()=>{
    console.info('我是方法')
}
const menus = ['菜单1','菜单2','菜单3']
const attrs = {
    href:'http://www.erppre.com',
    target:'_blank'
}
const element = (
    <div className="content-box">
        <Menu name="我是菜单" dispatch={customMethod}></Menu>
    </div>

    <ul>
    { menus.map((name, i) => <li key={i}>{name}</li>) }
    <a {...attrs}>这是个链接<a/>
    </ul>
);
  • 在JSX里原生dom元素都是小写字母开头,而自定义组件都是大写字母开头

  • 可以通过使用引号,来将属性值指定为字符串字面量

  • 可以使用大括号,来在属性值中插入一个 JavaScript 表达式

  • class 是保留词,所以添加样式时,需用 className 代替 class

  • 可以把数组映射为 JSX 元素列表

  • 可以用ES6的延展操作符扩充组件的props