这篇文章尝试将 Vue 中一些常见的功能在 React 中实现一遍,如果你恰巧是 Vue 转 React,期待对你有些帮助。
条件渲染
import React, { useState } from "react"export default function Vif (){const [ isShow, setIsShow ] = useState(true)const onToggleShow = () => {setIsShow(!isShow)}return (<div className="v-if"><button onClick={ onToggleShow }>切换</button>{/* 也可以用三目运算符 */}{/* { isShow ? <div>前端胖头鱼 显示出来啦</div> : null } */}{isShow && <div>前端胖头鱼 显示出来啦</div>}</div>)}
import React, { useState } from "react"export default function VShow (){const [ isShow, setIsShow ] = useState(true)const onToggleShow = () => {setIsShow(!isShow)}return (<div className="v-show"><button onClick={ onToggleShow }>切换</button>{<div style={{ display: isShow ? '' : 'none' }}>前端胖头鱼 显示出来啦</div>}</div>)}
列表渲染
在 React 没有类型 Vue 的 v-for 指令,我们可以采用 map 遍历的方式实现类似功能
import React, { useState } from "react"export default function VFor (){const [ list, setList ] = useState([{id: 1,name: '前端',},{id: 2,name: '后端',},{id: 3,name: 'android',},{id: 4,name: 'ios',},])return (<div className="v-for">{list.map((item) => {return <div className="v-for-item" key={ item.id }>{ item.name }</div>})}</div>)}
计算属性
React没有计算属性,但是我们可以通过useMemo这个hook来实现,和Vue computed不太一样的地方在于,我们必须手动维护依赖
import React, { useMemo, useState } from "react"export default function Computed (){const [ num1, setNum1 ] = useState(10)const [ num2, setNum2 ] = useState(10)const num3 = useMemo((a, b) => {return num1 + num2}, [ num1, num2 ])const onAdd = () => {setNum1(num1 + 10)}return (<div className="computed"><button onClick={ onAdd }>+10</button><div>计算结果:{ num3 }</div></div>)}
侦听器
React中要实现监听某些数据的变化执行响应的动作,可以使用useEffect
import React, { useState, useMemo, useEffect } from "react"import './watch.css'export default function Watch() {const [fetching, setFetching] = useState(false)const [selects, setSelects] = useState(['boy','girl'])const [selectValue, setSelectValue] = useState('')const result = useMemo(() => {return fetching ? '请求中' : `请求结果: 选中${selectValue || '~'}`}, [ fetching ])const onSelect = (value) => {setSelectValue(value)}const fetch = () => {if (!fetching) {setFetching(true)setTimeout(() => {setFetching(false)}, 1000)}}useEffect(() => {fetch()}, [ selectValue ])return (<div className="watch"><div className="selects">{selects.map((item, i) => {return <button key={ i } onClick={ () => onSelect(item) }>{ item }</button>})}</div><div className="result">{ result }</div></div>)}
Class 与 Style 绑定
有时候难免要给元素动态添加样式style,Vue和React都给我们提供了方便的使用方式。
在使用上基本大同小异:
相同点:
CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名
不同点:
- Vue可以通过数组语法绑定多个样式对象,React主要是单个对象的形式(这点Vue也可以)
- React 会自动添加 ”px”(这点Vue不会自动处理) 后缀到内联样式为数字的属性,其他单位手动需要手动指定
- React样式不会自动补齐前缀。如需支持旧版浏览器,需手动补充对应的样式属性。Vue中当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS property 时,如 transform,Vue.js 会自动侦测并添加相应的前缀。
import React from "react"export default function Style (){const style = {width: '100%',height: '500px',}const style2 = {backgroundImage: 'linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%)',borderRadius: '10px',}return (<div className="style" style={ { ...style, ...style2 } } ></div>)}
import React, { useMemo, useState } from "react"import './class.css' // 此处样式与上面是一样的export default function Class (){const [ isActive, setIsActive ] = useState(false)const buttonText = useMemo(() => {return isActive ? '已选中' : '未选中'}, [ isActive ])const buttonClass = useMemo(() => {// 和Vue中不太一样的是我们需要手动join一下,变成'button active'形式return [ 'button', isActive ? 'active' : '' ].join(' ')}, [ isActive ])const onClickActive = () => {setIsActive(!isActive)}return (<div className={ buttonClass } onClick={onClickActive}>{ buttonText }</div>)}

provide/inject
Vue和React中对于全局状态的管理都有各自好的解决方案,比如Vue中的Vuex,React中的redux和Mobx,当然小型项目中引入这些有点大材小用了,有没有其他解决方案呢?
Vue中可以使用provide/inject
React中则可以使用Context
假设全局有有一个用户信息userInfo的变量,需要在各个组件中都能便捷的访问到,在Vue和React中该如何实现呢?
import { createContext } from "react";export const UserInfoContext = createContext({userInfo: {name: ''}})
import { UserInfoContext } from './context/index'function App() {return (<BrowserRouter>// 注意这里<UserInfoContext.Providervalue={{ userInfo: { name: '前端胖头鱼' } }}><div className="title">我是React栗子</div><Routes><Route path="/v-if" element={<Vif />} /><Route path="/v-show" element={<VShow />} /><Route path="/v-for" element={<VFor />} /><Route path="/computed" element={<Computed />} /><Route path="/watch" element={<Watch />} /><Route path="/style" element={<Style />} /><Route path="/class" element={<Class />} /><Route path="/slot" element={<Slot />} /><Route path="/nameSlot" element={<NameSlot />} /><Route path="/scopeSlot" element={<ScopeSlot />} /><Route path="/provide" element={<Provide />} /></Routes></UserInfoContext.Provider></BrowserRouter>);}
import React, { useContext } from "react"import { UserInfoContext } from '../context/index'export default function Provide() {// 通过userContext,使用定义好的UserInfoContextconst { userInfo } = useContext(UserInfoContext)return (<div class="provide-inject">{ userInfo.name }</div>)}
