Dva - react状态管理 - 给vuex开发者
React Router 5.x - 给vuex开发者
Redux - 给vue开发者
根节点起始(Hook写法在下面)
create-react-app my-app
// 使用typescript
create-react-app my-app --template typescript
ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById("root"));
// 组件
class Clock extends React.Component {
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>现在是 {this.props.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(<Clock date="new Date()" />, document.getElementById("root"));
差别对照表
VUE | react |
---|---|
beforeMount(created?) | componentWillMount |
mounted | componentDidMount |
beforeDestroy | componentWillUnmount |
data | state (无双向绑定,需要 this.setState({})来更新视图) |
props | props |
slot | props(.children 为默认 slot,具名 slot 被当做一般属性传入) |
$refs | refs |
@click="fn" | onClick={this.fn} (fn 最好为剪头函数) |
v-model | 没有,自己实现 |
:class="{active: true}" | className={"active"} (仅字符串) |
:style="{color:'red'}" | style={{color:'red'}}) (可对象) |
没有@:,大括号是一切。下面详细说:
使用组件
props 无需声名,直接使用;需要对其进行格式验证时,可以使用 propTypes
class Welcome extends React.Component {
//propTypes: { 非必要
// name: React.PropTypes.string.isRequired,
//},
render(props) {
return (
<div>
<h1>Hello {props.name}!</h1>
{props.children} <!-- slot -->
{props.left} <!-- slot name="left" -->
</div>
);
}
}
ReactDOM.render(
<HelloMessage name="Vue" left={ <em /> }>
<p>xxxxxxx</p>
</HelloMessage>;,
document.getElementById('example')
);
组件内没有 vue 的 data,他用 state,一个意思
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()}; // vue的data
}
componentDidMount() {
this.timerID = setInterval(
() => this.setState({ date: new Date() }), // 改变data
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>现在是 {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('example')
);
事件绑定
class LoggingButton extends React.Component {
handleClick = e => { // 不用剪头函数,访问不到this
console.log('this is:', this);
}
render() {
return (
<button onClick={this.handleClick}> <!-- 与vue写法不同,react没有:@全是{} -->
Click me
</button>
);
}
}
条件渲染
没有 v-if,v-show,都是类 js 语法控制
class LoggingButton extends React.Component {
let button = null;
if (this.state.isLoggedIn) {
button = <a onClick={this.handleLogoutClick} />;
} else {
button = <a onClick={this.handleLoginClick} />;
}
render() {
return (
<div>
<h1>
// 方法1
{this.state.isLoggedIn && <span>你好{this.state.uname}</span>}
// 方法2
{this.state.isLoggedIn ? '退出登录' : '登录'}
</h1>
{button} // 方法3
</div>
);
}
}
列表绑定,使用 map
render(props, data) {
return (
<ul class="ul">
{data.list.map((item, index) =>
<item-movie data={item} key={index}></item-movie>
)}
</ul>
)
}
表单
没有 v-model,需要自己监听 change 事件
class 与 style
不可绑定对象
<!-- class要用className不可用对象,仅支持字符串 -->
<div className={index===this.state.currentIndex?"active":null}>此标签是否选中</div>
<!-- style可以用对象或字符串 -->
<h1 style={{color:'red',textAlign:'center'}}>Hello World!</h1>;
refs
this.refs => vue this.$refs
关于复用,没有 mixin,但引入高阶组件(HOC)的概念
即一个返回 React.Component 组件的函数,函数接受多个参数,在内部拼装出不同的组件。
but,都有 class 了为什么不用继承?
function withMixin(Comp, color) {
// ...并返回另一个组件...
return class extends React.Component {
constructor() {
super();
this.state = { ... };
}
componentDidMount() {
... getData ...
}
render() {
// ... 并使用新数据渲染被包装的组件!
// 请注意,我们可能还会传递其他属性
return <Comp data={this.state...} />;
}
};
}
const FinalComp = withMixin(trueComp, color);
关于它的一些原则:不要改变Comp
;不要在 render 方法中使用 HOC;不要忘记Comp
上的静态属性;
即js部分相同html不同的mixin,如果html相同js不同考虑使用组件将html封装?
命名规则 withXxxx
Hook
= React 16.8
根节点起始
ReactDOM.render(<h1>Hello, world!</h1>, document.getElementById("root"));
// 组件
import React, { useState } from "react";
function Clock() {
// 声明一个新的叫做 “count” 的 state 变量
const [count, setCount] = useState(0);
return (
<div>
<h2>现在是 {this.props.date.toLocaleTimeString()}.</h2>
<button onClick={() => setCount(count + 1)}>点击了 {count} 次</button>
</div>
);
}
差别对照表
import { useState, useEffect, useContext, useReducer } from "react";
Hook | CLASS |
---|---|
useEffect(cb, []) | componentDidMount\componentDidUpdate |
useEffect(cb, []) => fn | componentWillUnmount |
useEffect(cb, [attrName]) | (VUE)watch |
[a, setA] = useState(value) | state (无双向绑定,需要 this.setState({})来更新视图) |
同 CLASS | props |
同 CLASS | props(.children 为默认 slot,具名 slot 被当做一般属性传入) |
同 CLASS | refs |
onClick={fn} | onClick={this.fn} (fn 最好为剪头函数) |
同 CLASS | className={"active"} (仅字符串) |
同 CLASS | style={{color:'red'}}) (可对象) |
import { useState, useEffect } from "react";
function App() {
// 声明属性及其(更新视图的)变更方法
const [num, setNum] = useState(1);
useEffect(() => {
console.log("hook mounted"); // mounted
return () => console.log("hook beforeDestroy"); // beforeDestroy
}, []); // 影响??
return (
<div className="App">
<header className="App-header">
<p onClick={() => setNum(num + 1)}>
Edit <code>src/App.js</code> and save to reload.{num}
</p>
HOOK
</header>
</div>
);
}
自定义 Hook
如果App
的返回为一个值(非 jsx),则它是一个自定义 Hook
(命名规则 usrXxxx)。
可以理解为一种没有模板的组件?
hook 的 useState 与 class 中的 state
由于 react 不能直接修改 state,只支持整体覆盖原属性,所以在修改深层属性时需要拷贝对象 - 修改属性 - 覆盖原属性。
class 模式下所有调用都需要 this.xxx ,hook 可以直接使用 xxx
class 模式下方法需要使用剪头函数(或在构造函数中 bind(this)一下),hook 可以直接调用方法
VUE 与 REACT HOOK 差别对照表
VUE | react Hook |
---|---|
beforeMount(created?) | ?? |
mounted | useEffect(cb, []) |
beforeDestroy | useEffect(cb, []) => fn |
watch | useEffect(cb, [attrName]) |
data | [a, setA] = useState(value) |
props | props |
slot | props(.children 为默认 slot,具名 slot 被当做一般属性传入) |
$refs | refs |
@click="fn" | onClick={fn} |
v-model | 没有,自己实现 |
v-html | dangerouslySetInnerHTML={{ __html: htmlstr }} |
:class="{active: true}" | className={"active"} (仅字符串) |
:style="{color:'red'}" | style={{color:'red'}}) (可对象) |
mixin | 高阶函数? |
computed | 自定义 Hook? |
-
命名规则:高阶函数使用 withXxxx
使用方法类似继承
-
命名规则:自定义 Hook useXxxx
使用方法类似 vue 组件内由 $store.state 组成的计算属性
全局变量 Vue.prototype.theme(组件内 this.theme)
<Provider theme={theme}><app/></Provider>
(参见Provider及Context用法)