最近调部门,改用 React 开发了,整顿一些罕用知识点。
更多内容还请参考:
React 中文文档
Ant Design
1. 我的项目创立
# 创立我的项目
npx create-react-app your-project-name
# antd
npm 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";
// 在组件中引入 antd
import {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
拜访props
和state
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)