最近调部门,改用React开发了,整顿一些罕用知识点。

更多内容还请参考:
React 中文文档
Ant Design

1. 我的项目创立

# 创立我的项目npx create-react-app your-project-name# antdnpm i antd# 路由npm i react-router-dom

2. 启动服务

npm start
Vue 脚手架构建的我的项目应用 npm run serve

3. 装置插件

VS Code装置ES 7,十分不便生成组件代码

创立 Login.js 文件

输出 rfce 按回车,就能够初始化一个组件代码

import React from 'react'function Login() {    return (        <div>                </div>    )}export default Login

4. 创立路由

1)简略实现

关上根目录中的 index.js 文件,引入路由模块,增加如下代码:

import React from 'react';import ReactDOM from 'react-dom';// 引入路由模块,应用哈希路由import { HashRouter as Router, Switch, Route } from 'react-router-dom';import './index.css';// 引入组件// 不必本人引入,当用到的时候,编辑器会主动增加import Login from './pages.Login';import List from './pages/admin/products/List';ReactDOM,render(<Router>    <Switch>        <Route path="/login" component={Login} />        <Route path="/admin/products" component={List} />    </Switch></Router>, document.getElementById('root'));
React 外面的 index.js 相当于 Vue 的 main.js 文件

2)失常用法

在开发中个别不会这样写,而是在根目录下建一个 routes 目录,在 routes 目录下建 index.js 文件,增加如下代码:

import Login from "../pages/Login";import Index from "../pages/admin/dashboard/Index";import List from "../pages/admin/products/List";import Edit from "../pages/admin/products/Edit";// 一般页面路由export const mainRoutes = [{    path: '/login',    component: Login}, {    path: '/404',    component: PageNotFound}]// 须要鉴权的路由export const adminRoutes = [{    path: '/admin/dashboard',    component: Index}, {    path: '/admin/products',    component: List,    exact: true // 路由path和上面反复了,须要设置一下,只匹配以后path}, {    path: '/admin/products/edit/:id',    component: Edit}]

而后 index.js 文件能够改成上面这样:

import React from 'react';import ReactDOM from 'react-dom';// 引入路由模块,应用哈希路由import {    HashRouter as Router,    Switch,    Route,    Redirect} from 'react-router-dom';import './index.css';import { mainRoutes } from "./routes";ReactDOM,render(    <Router>        <Switch>            { mainRoutes.map(route => {                // return <Route key={route.path} path={route.path} component={route.component} />                // 因为route外面的key也是path和component,所以能够间接用ES6延展运算符                return <Route key={route.path} {...route} />            }) }            <!-- 当找不到页面的时候就重定向到404 -->            <Redirect to="/404" />        </Switch>    </Router>,    document.getElementById('root'));

3)嵌套路由

当拜访的地址以 /admin 结尾的时候,都走 App 这个容器。

index.js 文件中再加一个 Route,代码如下:

import React from 'react';import ReactDOM from 'react-dom';import {    HashRouter as Router,    Switch,    Route,    Redirect} from 'react-router-dom';import './index.css';import App from "./App";import { mainRoutes } from "./routes";ReactDOM,render(    <Router>        <!-- 这里再加一个Route,把路由属性传过来 -->        <Route path="/admin" render={routeProps => <App {...routeProps} />} />        <Switch>            { mainRoutes.map(route => {                return <Route key={route.path} {...route} />            }) }            <Redirect to="/404" />        </Switch>    </Router>,    document.getElementById('root'));

而后在 App.js 外面增加如下代码:

import React from 'react';import { Switch, Route, Redirect } from 'react-router-dom';import { adminRoutes } from './routes';function App() {    return (        <div className="App">            <h1>这是App组件</h1>            <Switch>                {adminRoutes.map(route => {                    return (                        <Route                            key={route.path}                            path={route.path}                            exact={route.exact}                            render={routeProps => {                                return <route.component {...routeProps} />                            }}                        />                    )                })}                <Redirect to="/404" />            </Switch>        </div>    )}export default App
React 外面的 <Switch> 相当于 Vue 的 <router-view>

问题:Vue 能够间接定义嵌套路由,React 能够吗

5. 搭建页面框架

1)组件中引入图片

import React from 'react';import logo from "./logo.png";function App() {    return (        <div className="logo">            <img src={logo} alt="logo" />        </div>    )}export default App

2)定义行内款式

import React from 'react';function App() {    return (        <div style={{ background: "#fff" }}>        </div>        <div style={{ height: "100%", borderRight: 0 }}>        </div>        <div style={{ padding: "0 24px 24px" }}>        </div>        <div style={{ margin: "16px 0" }}>        </div>    )}export default App
在 React 中 {} 外部其实就是 JS 表达式

款式其实是以 JS 对象模式定义的

style 看上去是双大括号,但其实两层括号是不一样的,外层括号代表外面定义的是 JS 表达式,内层括号代表 JS 对象

3)路由点击跳转

import React from 'react';// 在组件中应用路由须要用到 withRouter 插件,否则会报错import { withRouter } from "react-router-dom";// 在组件中引入 antdimport { Layout, Menu, Breadcrumb, Icon } from "antd";import { adminRoutes } from "../../routes/index";const routes = adminRoutes.filter(route => route.isShow);function Index() {    return (        <Menu            mode="inline"            defaultSelectedKeys={["1"]}            defaultOpenKeys={["sub1"]}            style={{ height: "100%", borderRight: 0 }}        >            {routes.map(route => {                return (                    <Menu.Item                        key={route.path}                        onClick={p => props.history.push(p.key)}                    >                        <Icon type={route.icon}                        {route.title}                    </Menu.Item>                )            })}        </Menu>    )}export default withRouter(Index); // 这里须要把组件套进去
问题:Vue 能够间接通过全局办法 this.$router.push() 实现路由跳转,React 没有吗

问题:React 的 antd 组件是否全局注册

4)列表页面搭建

import React from 'react';import { Card, Table, Button, Popconfirm } from "antd";// 数据源const dataSource = [{    id: 1,    name: "Jack",    price: 8888}, {    id: 2,    name: "Pony",    price: 2333}, {    id: 3,    name: "Eric",    price: 9999}]function List() {    // 表头字段    const columns = [{        title: '序号',        key: "id",        width: 80,        align: "center",        render: (txt, record, index) => index + 1 // 自定义字段类型    }, {        title: "名字",        dataIndex: "name" // 对应 dataSource 外面的 name 字段    }, {        title: "价格",        dataIndex: "price" // 对应 dataSource 外面的 price 字段    }, {        title: "操作",        render: (txt, record, index) => {            return (                <div>                    <Button type="primary" size="small">批改</Button>                    <Popconfirm                        title="确定删除此项?"                        onCancel={() => console.log("用户勾销删除!")}                        onConfirm={() => console.log("用户确认删除!")}                    >                        <Button style={{ margin: "0 1rem" }} size="small">删除</Button>                    </Popconfirm>                </div>            )        }    }]        return (        <Card            title="商品列表"            extra={                <!-- 这里是扩大项 -->                <Button type="primary" size="small">                    新增                </Button>            }        >            <Table columns={columns}                   bordered                   dataSource={dataSource}            />        </Card>    )}export default List;
React 列表自定义字段类型通过 render 实现, 在 Vue 中则是通过 slot 实现

6. 函数组件和 Class 组件

函数组件适宜一些比较简单的利用场景,只承受里面传进来的 props , 没有本人的公有数据 state :

function Clock(props) {  return (    <div>      <h1>Hello, world!</h1>      <h2>It is {props.date.toLocaleTimeString()}.</h2>    </div>  );}

如果须要用到公有数据 state 就要创立 Class 组件,Class 须要继承 React.Component

class Clock extends React.Component {  constructor(props) {    super(props);    this.state = {date: new Date()};  }  render() {    return (      <div>        <h1>Hello, world!</h1>        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>      </div>    );  }}
Class 组件的 render() 办法返回的货色就是函数组件外面的内容

render() 办法外面须要通过 this 拜访 propsstate

7. 事件处理

在 React 中事件的命名采纳小驼峰法,而在传统 HTML 中是纯小写。

<button onClick={activateLasers}>  Activate Lasers</button>

在 React 中必须显式地应用 preventDefault 阻止默认事件,而在传统 HTML 中能够间接 return false ,代码如下:

function ActionLink() {  function handleClick(e) {    e.preventDefault();    console.log('The link was clicked.');  }  return (    <a href="#" onClick={handleClick}>      Click me    </a>  );}
在这里,e 是一个合成事件。React 事件与原生事件不完全相同。

1)事件处理函数 this 的绑定

a)在结构器中绑定 this

在 JavaScript 中,class 的办法默认不会绑定 this。如果你遗记绑定 this.handleClick 并把它传入了 onClick,当你调用这个函数的时候 this 的值为 undefined

class Toggle extends React.Component {  constructor(props) {    super(props);    this.state = {isToggleOn: true};    // 为了在回调中应用 `this`,这个绑定是必不可少的    this.handleClick = this.handleClick.bind(this);  }  handleClick() {    this.setState(state => ({      isToggleOn: !state.isToggleOn    }));  }  render() {    return (      <button onClick={this.handleClick}>        {this.state.isToggleOn ? 'ON' : 'OFF'}      </button>    );  }}

如果感觉应用 bind 很麻烦,这里有两种形式能够解决。

b)应用 class fields

一种是能够应用 class fields 正确的绑定回调函数,Create React App 默认启用此语法:

class LoggingButton extends React.Component {  // 此语法确保 `handleClick` 内的 `this` 已被绑定。  // 留神: 这是 *实验性* 语法。  handleClick = () => {    console.log('this is:', this);  }  render() {    return (      <button onClick={this.handleClick}>        Click me      </button>    );  }}

c)应用箭头函数

另一种是能够在回调中应用箭头函数,此语法问题在于每次渲染 LoggingButton 时都会创立不同的回调函数。在大多数状况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额定的从新渲染:

class LoggingButton extends React.Component {  handleClick() {    console.log('this is:', this);  }  render() {    // 此语法确保 `handleClick` 内的 `this` 已被绑定。    return (      <button onClick={() => this.handleClick()}>        Click me      </button>    );  }}

2)向事件处理函数传递参数

上面两种形式是等价的。如果通过箭头函数的形式,事件对象必须显式的进行传递,而通过 bind 的形式,事件对象以及更多的参数会被隐式的进行传递。

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button><button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

8. 条件渲染

根底用法:

class LoginControl extends React.Component {  constructor(props) {    super(props);    this.state = {isLoggedIn: false};  }  render() {    const isLoggedIn = this.state.isLoggedIn;    let button;    if (isLoggedIn) {      button = <LogoutButton onClick={this.handleLogoutClick} />;    } else {      button = <LoginButton onClick={this.handleLoginClick} />;    }    return (      <div>        <Greeting isLoggedIn={isLoggedIn} />        {button}      </div>    );  }}

与运算符 &&

render() {  const count = 0;  return (    <div>      { count && <h1>Messages: {count}</h1>}    </div>  );}
之所以能这样做,是因为在 JavaScript 中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。因而,如果条件是 true&& 右侧的元素就会被渲染,如果是 false,React 会疏忽并跳过它。

在下面的代码中,如果 count 的值为0,还是会进行渲染。

三元运算符

render() {  const isLoggedIn = this.state.isLoggedIn;  return (    <div>      {isLoggedIn        ? <LogoutButton onClick={this.handleLogoutClick} />        : <LoginButton onClick={this.handleLoginClick} />      }    </div>  );}

9. 状态晋升

实际上就是子组件向父组件传参

子组件代码:

class TemperatureInput extends React.Component {  constructor(props) {    super(props);    this.handleChange = this.handleChange.bind(this);  }  handleChange(e) {    // 向外传递自定义事件    this.props.onTemperatureChange(e.target.value);  }  render() {    const temperature = this.props.temperature;    const scale = this.props.scale;    return (      <fieldset>        <legend>Enter temperature in {scaleNames[scale]}:</legend>        <input value={temperature}               onChange={this.handleChange} />      </fieldset>    );  }}

父组件代码:

class Calculator extends React.Component {  constructor(props) {    super(props);    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);    this.state = {temperature: '', scale: 'c'};  }  <!-- 自定义事件处理函数 -->  handleCelsiusChange(temperature) {    this.setState({scale: 'c', temperature});  }  render() {    const scale = this.state.scale;    const temperature = this.state.temperature;    const celsius = scale === 'f' ? tryConvert(temperature, toCelsius) : temperature;    const fahrenheit = scale === 'c' ? tryConvert(temperature, toFahrenheit) : temperature;    return (      <div>        <!-- 绑定自定义事件处理函数 -->        <TemperatureInput          scale="c"          temperature={celsius}          onTemperatureChange={this.handleCelsiusChange} />        <BoilingVerdict          celsius={parseFloat(celsius)} />      </div>    );  }}
在 React 中应用 this.props.onTemperatureChange(e.target.value); 向外传递事件同时携带参数

相当于 Vue 中的 this.$emit("onTemperatureChange", e.targetvalue)