Open gaoryrt opened 6 years ago
// vue
<div id="app">
{{ message }}
</div>
var app = new Vue({
el: '#app',
data: {
message: 'Hello Vue!'
}
})
// react component
class App extends Component {
constructor() {
super()
this.state = {
message: 'Hello React!'
}
}
render() {
return (
<div id="app">
{ this.state.message }
</div>
)
}
}
// react stateless component
function App() {
const [message, _] = useState('Hello React!')
return (
<div id="app">
{message}
</div>
)
}
// vue
<div id="app-2">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
var app2 = new Vue({
el: '#app-2',
data: {
message: '页面加载于 ' + new Date().toLocaleString()
}
})
// react component
class App extends Component {
constructor() {
super()
this.state = {
message: '页面加载于 ' + new Date().toLocaleString()
}
}
render() {
return (
<div id="app-2">
<span title={ this.state.message }>
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
)
}
}
// react stateless comp
function App() {
const [message, _] = useState('页面加载于 ' + new Date().toLocaleString())
return <div id="app-2">
<span title={message}>
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
}
// vue
<div id="app-3">
<p v-if="seen">现在你看到我了</p>
</div>
var app3 = new Vue({
el: '#app-3',
data: {
seen: true
}
})
// react comp
class App extends Component {
constructor() {
super()
this.state = {
seen: false
}
}
render() {
return (
<div id="app-3">
{
this.state.seen && // this.state.seen ?
<p> // <p>
现在你看到我了 // 现在你看到我了
</p> // </p> : null
}
</div>
)
}
}
// react stateless comp
function App() {
const [seen, _] = useState(false)
return <div id="app-3">
{seen && <p>现在你看到我了</p>}
</div>
}
// vue
<div id="app-4">
<ol>
<li v-for="todo in todos">
{{ todo.text }}
</li>
</ol>
</div>
var app4 = new Vue({
el: '#app-4',
data: {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 Vue' },
{ text: '整个牛项目' }
]
}
})
// react comp
class App extends Component {
constructor() {
super()
this.state = {
todos: [
{ text: '学习 JavaScript' },
{ text: '学习 React' },
{ text: '整个牛项目' }
]
}
}
render() {
return (
<div id="app-4">
{
this.state.todos.map(todo =>
<li>{ todo.text }</li>
)
}
</div>
)
}
}
// react stateless comp
function App() {
const [todos, _] = useState([
{ text: '学习 JavaScript' },
{ text: '学习 React' },
{ text: '整个牛项目' }
])
return <div id="app-4">
{todos.map(todo =>
<li>{todo.text}</li>
)}
</div>
}
// vue
<div id="app-5">
<p>{{ message }}</p>
<button v-on:click="reverseMessage">逆转消息</button>
</div>
var app5 = new Vue({
el: '#app-5',
data: {
message: 'Hello Vue.js!'
},
methods: {
reverseMessage: function () {
this.message = this.message.split('').reverse().join('')
}
}
})
// react comp
class App extends Component {
constructor() {
super()
this.state = {
message: 'Hello React.js!'
}
}
reversMessage() {
this.setState(state => ({
message: state.message.split('').reverse().join('')
}))
}
render() {
return (
<div id="app-5">
<p>{ this.state.message }</p>
<button onClick={ () => this.reversMessage() }>逆转消息</button>
</div>
)
}
}
// react stateless comp
function App() {
const [message, setMessage] = useState('Hello React.js!')
return <div id="app-5">
<p>{message}</p>
<button onClick={_ => setMessage(message.split('').reverse().join(''))}>
逆转消息
</button>
</div>
}
// vue
<div id="app-6">
<p>{{ message }}</p>
<input v-model="message">
</div>
var app6 = new Vue({
el: '#app-6',
data: {
message: 'Hello Vue!'
}
})
// react comp
class App extends Component {
constructor() {
super()
this.state = {
message: 'Hello React!'
}
}
handleChange(e) {
this.setState({message: e.target.value})
}
render() {
return (
<div id="app-6">
<p>{ this.state.message }</p>
<input
value={ this.state.message }
onChange={ e => this.handleChange(e) }
/>
</div>
)
}
}
// react stateless comp
function App() {
const [message, setMessage] = useState('Hello React!')
return <div id="app-6">
<p>{ message }</p>
<input
value={ message }
onChange={ e => setMessage(e.target.value) }
/>
</div>
}
<div id="app-7">
<ol>
<todo-item
v-for="item in groceryList"
v-bind:todo="item"
v-bind:key="item.id">
</todo-item>
</ol>
</div>
Vue.component('todo-item', {
props: ['todo'],
template: '<li>{{ todo.text }}</li>'
})
var app7 = new Vue({
el: '#app-7',
data: {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
})
const TodoItem = ({text}) =>
<li>{ text }</li>
class App extends Component {
constructor() {
super()
this.state = {
groceryList: [
{ id: 0, text: '蔬菜' },
{ id: 1, text: '奶酪' },
{ id: 2, text: '随便其它什么人吃的东西' }
]
}
}
render() {
return (
<div id="app-7">
<ol>
{
this.state.groceryList.map(({ id, text })=>
<TodoItem key={ id } text={ text }></TodoItem>
)
}
</ol>
</div>
)
}
}
顶一个!
不太会Vue, @gaoryrt 还请补充Vue实现类似功能的对比。(不知道是不是主题之外了,全当增加活跃度来了,有错地方还请补充 = =! )
class App extends Component {
constructor () {
super()
this.inputRef = React.createRef()
}
componentDidMount () {
this.inputRef.current.focus()
}
render () {
return (
<form>
<input ref={this.inputRef} />
</form>
)
}
}
const Sub1= React.lazy(() => import('./Sub1'))
const Sub2 = React.lazy(() => import('./Sub2'))
class App extends Component {
render () {
return (
<div>
<React.Suspense fallback={<div>Loading</div>}>
<Router>
<Switch>
<Route path='/sub1' component={Sub1} />
<Route path='/sub2' component={Sub2} />
</Switch>
</Router>
</React.Suspense>
</div>
)
}
}
function withHOC(WrappedComponent) {
return calss extends Component {
// do anything you want
render () {
const { extra, ...otherProps } = this.props
const newProp = fromStateOrMethod
return (
<WrappedComponent
newProp={newProp}
{...otherProps}
/>
)
}
}
}
class App extends Component {
constructor() {
// 初始化,设置state等
}
componentWillMount() {
// 第一次render之前调用
}
componentDidMount () {
// 第一次render之后调用, 在这里进行异步操作
}
componentWillReceiveProps (nextProps) {
// 父组件的状态发生变化会子组件会调用该方法,nextProps是传递过来新props
}
shouldComponentUpdate () {
// 决定是否更新,建议使用:PureComponent
}
componentWillUpdate () {
// 更新前调用
}
componentDidUpdate () {
// 更新render之后调用, 不要在这里进行setState, 会导致死循环
}
componentDidCatch () {
// 子组件的异常会倍这个方法捕获,但不能捕获自己组件产生的异常。
// 可以定义一个ErrorBoundary组件在最外层,将捕获的错误统一处理(例如可以:sentry到服务器)
}
componentWillUnmount () {
// 组件unmount之前会调用
}
render () {
// 渲染
}
}
<div id="ref-demo">
<input ref="inputRef">
</div>
var refdemo = new Vue({
el: '#ref-demo',
mounted() {
this.$nextTick( // mounted + $nextTick 对应 componentDidMount
() => this.$refs.inputRef.focus()
)
}
})
callback ref
class App extends Component {
componentDidMount () {
this._inputRef.focus()
}
render () {
return (
<input ref={ n => this._inputRef = n } />
)
}
}
createRef
class App extends Component {
constructor () {
super()
this.inputRef = React.createRef()
}
componentDidMount () {
this.inputRef.current.focus()
}
render () {
return (
<input ref={ this.inputRef } />
)
}
}
本篇主题是 v-语法 到 jsx
,旨在使用 react 实现一些 vue 封装的语法糖
这样来说,具有相似 api 的 子组件引用 和 高阶组件 都能直观看出写法异同
但是由于 vue 高度封装的原因,实现其他两个例子确实不如自由的 react 来得简洁
下面的几个就相当于用 vue 实现 react 了
路由有 vue-router,异步组件 loading 有 高级异步组件的工厂函数 vue-router 可以匹配路由,代码分割,动态加载,可惜不能匹配 loading 高级异步组件可以代码分割,动态加载,匹配 loading,但是不能匹配路由 这里就需要根据需求自己实现了
const Sub1= React.lazy(() => import('./Sub1'))
const Sub2 = React.lazy(() => import('./Sub2'))
class App extends Component {
render () {
return (
<div>
<React.Suspense fallback={<div>Loading</div>}>
<Router>
<Switch>
<Route path='/sub1' component={Sub1} />
<Route path='/sub2' component={Sub2} />
</Switch>
</Router>
</React.Suspense>
</div>
)
}
}
Vue.use(vueRouter)
const router = new vueRouter({
routes: [
{ path: '/sub1', component: () => import('./sub1') },
{ path: '/sub2', component: () => import('./sub2') }
]
})
const app = new Vue({
data: { loading: false },
template: `<div>
<div v-if="loading">loading</div>
<router-view v-else />
</div>`,
router
}).$mount('#app')
router.beforeEach((to, from, next) => {
app.loading = true
next()
})
router.afterEach(() => {
app.loading = false
})
vue 里面最接近的语法应该是 mixin 但是 react mixin 都被废弃挺久的了 这里就需要根据需求自己实现了
function withHOC(WrappedComponent) {
return calss extends Component {
// do anything you want
render () {
const { extra, ...otherProps } = this.props
const newProp = fromStateOrMethod
return (
<WrappedComponent
newProp={newProp}
{...otherProps}
/>
)
}
}
}
function withHOC(WrappedComponent) {
const { extra, ...otherProps } = WrappedComponent.props
const newProp = fromStateOrMethod
return {
props: otherProps.concat(newProp),
render (h) {
return h(WrappedComponent, {
on: this.$listeners,
attrs: this.$attrs,
props: this.$props
})
}
}
}
更多讨论:Discussion: Best way to create a HOC 包括 slot 的实现:探索Vue高阶组件
react | vue |
---|---|
constructor | data() 里 return 前 |
componentWillMount | beforeMount(){} |
render | template 、render(){} 、<component> 里 |
componentDidMount | mounted(){} |
componentWillReceiveProps | watch 里手动绑定 |
shouldComponentUpdate | |
componentWillUpdate | beforeUpdate(){} |
componentDidUpdate | updated(){} |
componentDidCatch | |
componentWillUnmount | beforeDestroy(){} |
点错关闭了。。。
期待更深入的分析
话说 hook 出来了有些地方可以好好改改
这篇只记录了几个 vue 语法糖在 react jsx 中的实现,可以稍微直观对比一下二者的异同 (越发感觉 react 的定位和 vue 不同,react 比 vue 还要 view 一点 (当然 react 的写法很自由,我这里就不列举了 (我也是渣渣,有不对的地方麻烦指出来,共同学习