【建议收藏】11+实战技巧,让你轻松从Vue过渡到React

2023-11-06

前言

在这个卷神辈出的时代,只是熟练Vue的胖头鱼,已经被毒打过多次了,面试中曾被质疑:“你居然不会React?”我无语凝噎,不知说啥是好。

这篇文章尝试将Vue中一些常见的功能在React中实现一遍,如果你恰巧是VueReact,或者ReactVue,期待对你有些帮助。

如果你是一名熟悉ReactVue的同学跪求轻喷(手动求生)

每个功能,都有对应的Vue和React版本实现,也有对应的截图或者录屏

Vue仓库

React仓库

1. v-if

我们先从最常见的显示隐藏开始,Vue中处理一个元素的显示隐藏一般会用v-if或者v-show指令,只不过v-if是“真正”的条件渲染,切换过程中条件块内的事件监听器和子组件会适当地被销毁和重建。而v-show就简单了,只是css样式上的控制。

v-if源代码点这里

Vue

<template>
  <div class="v-if">
    <button @click="onToggleShow">切换</button>
    <div v-if="isShow">前端胖头鱼 显示出来啦</div>
  </div>
</template>

<script>
export default {
  name: 'vif',
  data () {
    return {
      isShow: true
    }
  },
  methods: {
    onToggleShow () {
      this.isShow = !this.isShow
    }
  }
}
</script>

React

vif源代码点这里

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>
  )
}

预览

102e85dc7e5de5e97a9739f518f563f4.gif
v-if.gif

2. v-show

同上,这次我们通过v-show来实现显示隐藏的功能,同时观察DOM的样式变化

注意: 这里为啥显示的时候不设置为block是因为有些元素本身不是块级元素,如果强行设置为block有可能导致错误的样式。

Vue

v-show源代码点击这里

<template>
  <div class="v-show">
    <button @click="onToggleShow">切换</button>
    <div v-show="isShow">前端胖头鱼 显示出来啦</div>
  </div>
</template>

<script>
export default {
  name: 'vshow',
  data () {
    return {
      isShow: true
    }
  },
  methods: {
    onToggleShow () {
      this.isShow = !this.isShow
    }
  }
}
</script>

React

vShow源代码点这里

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>
  )
}

预览



bd0e8cca63d6b7e0a2e0ef551334d895.gif


3. v-for

一般情况下,渲染一个列表在Vue中使用v-for指令,v-for 指令需要使用 item in items 形式的特殊语法,其中 items 是源数据数组,而 item 则是被迭代的数组元素的别名。当然了,每个元素都需要设置唯一的key

Vue

v-for源代码点这里

<template>
  <div class="v-for">
    <div 
      class="v-for-item"
      v-for="item in list"
      :key="item.id"
    >
      {{ item.name }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'vfor',
  data () {
    return {
      list: [
        {
          id: 1,
          name: '前端',
        },
        {
          id: 2,
          name: '后端',
        },
        {
          id: 3,
          name: 'android',
        },
        {
          id: 4,
          name: 'ios',
        },
      ]
    }
  }
}
</script>

React

React没有v-for指令,我们可以采用map遍历的方式实现类似功能

vFor源代码点这里

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>
  )
}

预览

de1c78cb54d5910d1f9582ac7949a926.png
v-for.png

4. computed

当某个变量需要依赖其他变量求值时,使用计算属性会非常方便,并且Vue的计算属性是基于它们的响应式依赖进行缓存的,依赖值未发生变化,不会重新计算,达到缓存的作用。

我们来看一个简单的加法例子:num3num1num2相加所得,同时按钮每点一次num1加10,num3也会跟着不断加10

Vue

computed源代码点这里

<template>
  <div class="computed">
    <button @click="onAdd">+10</button>
    <div>计算结果:{{ num3 }}</div>
  </div>
</template>

<script>
export default {
  name: 'computed',
  data () {
    return {
      num1: 10,
      num2: 10,
    }
  },
  computed: {
    num3 () {
      return this.num1 + this.num2
    }
  },
  methods: {
    onAdd () {
      this.num1 += 10
    }
  }
}
</script>

React

React没有计算属性,但是我们可以通过useMemo这个hook来实现,和Vue computed不太一样的地方在于,我们必须手动维护依赖

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>
  )
}

预览

73cfb81871aba2cfb43b590814c8b371.gif
computed.gif

5. watch

有时候我们需要监听数据变化然后执行异步行为或者开销较大的操作时,在Vue中可以使用watch来实现

我们来模拟一个这样的场景并且通过watch来实现:选择boy或者girl,选中后发送请求,显示请求结果。(这里通过setTimeout模拟异步请求过程)

Vue

watch源代码点这里

<template>
  <div class="watch">
    <div class="selects">
      <button 
        v-for="(item, i) in selects"
        :key="i"
        @click="onSelect(item)"
      >
        {{ item }}
      </button>
    </div>
    <div class="result">
      {{ result }}
    </div>
  </div>
</template>

<script>
export default {
  name: 'watch',
  data () {
    return {
      fetching: false,
      selects: [
        'boy',
        'girl'
      ],
      selectValue: ''
    }
  },
  computed: {
    result () {
      return this.fetching ? '请求中' : `请求结果: 选中${this.selectValue || '~'}`
    }
  },
  watch: {
    selectValue () {
      this.fetch()
    }
  },
  methods: {
    onSelect (value) {
      this.selectValue = value  
    },
    fetch () {
      if (!this.fetching) {
        this.fetching = true

        setTimeout(() => {
          this.fetching = false
        }, 1000)
      }
    }
  }
}
</script>

React

React中要实现监听某些数据的变化执行响应的动作,可以使用useEffect

watch源代码点这里

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>
  )
}

预览

d7519c75045dad64664661beadd8eafe.gif
watch.gif

6. style

有时候难免要给元素动态添加样式styleVueReact都给我们提供了方便的使用方式。

在使用上基本大同小异:

相同点:

CSS property 名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case,记得用引号括起来) 来命名

不同点:

  1. Vue可以通过数组语法绑定多个样式对象,React主要是单个对象的形式(这点Vue也可以)

  2. React 会自动添加 ”px”(这点Vue不会自动处理) 后缀到内联样式为数字的属性,其他单位手动需要手动指定

  3. React样式不会自动补齐前缀。如需支持旧版浏览器,需手动补充对应的样式属性。Vue中当 v-bind:style 使用需要添加浏览器引擎前缀的 CSS property 时,如 transform,Vue.js 会自动侦测并添加相应的前缀。

Vue

style源代码点这里

<template>
  <div class="style" :style="[ style, style2 ]"></div>
</template>

<script>
export default {
  name: 'style',
  data () {
    return {
      style: {
        width: '100%',
        height: '500px',
      },
      style2: {
        backgroundImage: 'linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%)',
        borderRadius: '10px',
      }
    }
  }
}
</script>

React

style源代码点这里

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>
  )
}

预览

24d4dbaefcd17ef111eb5e1766b8f7aa.png
style.png

7. class

如何动态地给元素添加class?Vue中我自己比较喜欢用数组的语法(当然还有对象的写法),React中也可以使用一些第三方包如classnames起到更加便捷添加class的效果。

下面我们看下不借助任何库,如何实现按钮选中的效果

Vue

class源代码点这里

<template>
  <button :class="buttonClasses" @click="onClickActive">{{ buttonText }}</button>
</template>

<script>
export default {
  name: 'class',
  data () {
    return {
      isActive: false,
    }
  },
  computed: {
    buttonText () {
      return this.isActive ? '已选中' : '未选中'
    },
    buttonClasses () {
   // 通过数组形式维护class动态列表   
      return [ 'button', this.isActive ? 'active' : '' ]
    }
  },
  methods: {
    onClickActive () {
      this.isActive = !this.isActive
    }
  }
}
</script>

<style scoped>
.button{
  display: block;
  width: 100px;
  height: 30px;
  line-height: 30px;
  border-radius: 6px;
  margin: 0 auto;
  padding: 0;
  border: none;
  text-align: center;
  background-color: #efefef;
}

.active{
  background-image: linear-gradient(120deg, #84fab0 0%, #8fd3f4 100%);
  color: #fff
}

</style>

React

class源代码点这里

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>
  )
}

预览

79bf4d78d39561e549adf107ed7390db.gif


8.provide/inject

Vue和React中对于全局状态的管理都有各自好的解决方案,比如Vue中的Vuex,React中的reduxMobx,当然小型项目中引入这些有点大材小用了,有没有其他解决方案呢?

Vue中可以使用provide/inject

React中则可以使用Context

假设全局有有一个用户信息userInfo的变量,需要在各个组件中都能便捷的访问到,在Vue和React中该如何实现呢?

Vue

Vue中借用provide/inject可以将顶层状态,传递至任意子节点,假设我们再app.vue中声明了一个userInfo数据

provide源代码点这里

app.vue

<template>
  <div id="app">
    <div class="title">我是Vue栗子</div>
    <router-view/>
  </div>
</template>
<script>

export default {
  name: 'app',
  // 声明数据 
  provide () {
    return {
      userInfo: {
        name: '前端胖头鱼'
      }
    }
  }
}
</script>

provide.vue

<template>
  <div class="provide-inject">{{ userInfo.name }}</div>
</template>

<script>
export default {
  name: 'provideInject',
  // 使用数据
  inject: [ 'userInfo' ]
}
</script>

React

React中要实现类似的功能,可以借助Context,将全局状态共享给任意子节点

provide源代码点这里

context/index.js

import { createContext } from "react";

export const UserInfoContext = createContext({
  userInfo: {
    name: ''
  }
})

app.js

import { UserInfoContext } from './context/index'

function App() {
  return (
    <BrowserRouter>
      // 注意这里
      <UserInfoContext.Provider
        value={{ 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>
  );
}

provide.js

import React, { useContext } from "react"
import { UserInfoContext } from '../context/index'


export default function Provide() {
  // 通过userContext,使用定义好的UserInfoContext
  const { userInfo } = useContext(UserInfoContext)

  return (
    <div class="provide-inject">{ userInfo.name }</div>
  )
}

预览

605a06aaa42a25fb7fe51b87f22b3627.png
4127923929-provide.png

9. slot(默认插槽)

插槽是Vue中非常实用的功能,我把他理解成”坑位“,等待着你从外面把他填上,而这个”坑位“可以分成默认坑位具名坑位作用域坑位,咱们通过一个实战例子来看看React中如何实现同等的功能。

假设我们要实现一个简单的dialog组件,基本功能是标题可以传字符串,内容部分可以完全自定义,应该怎么实现呢?

f90e0699d116c37336212d9a5a730e5a.gif


Vue

slot源代码点这里

dialog

<template>
  <div class="dialog" v-show="visible">
    <div class="dialog-mask" @click="onHide"></div>
    <div class="dialog-body">
      <div class="dialog-title" v-if="title">{{ title }}</div>
      <div class="dialog-main">
  // 注意这里放了一个默认插槽坑位
        <slot></slot>
      </div>
      <div class="dialog-footer">
        <div class="button-cancel" @click="onHide">取消</div>
        <div class="button-confirm" @click="onHide">确定</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "dialog",
  props: {
    title: {
      type: String,
      default: "",
    },
    visible: {
      type: Boolean,
      default: false,
    },
  },
  methods: {
    onHide () {
      this.$emit('update:visible', false)
    }
  }
};
</script>

slot

<template>
  <div class="slot">
    <button @click="onToggleVisible">切换dialog</button>
    <Dialog
      :visible.sync="visible"
      title="默认插槽"
    >
   // 这里会替换到<slot></slot>的位置处
   <div class="slot-body">前端胖头鱼</div>
    </Dialog>
  </div>
</template>

<script>
import Dialog from './components/dialog.vue'

export default {
  name: 'slot',
  components: {
    Dialog,
  },
  data () {
    return {
      visible: false
    }
  },
  methods: {
    onToggleVisible () {
      this.visible = !this.visible
    }
  }
}

React

要在React中同样实现上面的功能应该怎么办呢?React可没有啥插槽啊!别急,虽然React中没有插槽的概念,但是却可以通过props.children获取到组件内部的子元素,通过这个就可以实现默认插槽的功能

slot源代码点这里

Dialog

import React, { useState, useEffect } from "react"

import './dialog.css'

export default function Dialog(props) {
  // 原谅我用visible -1这种傻叉的方式先实现了, 重点不是在这里
  const { children, title = '', visible = -1 } = props
  const [visibleInner, setVisibleInner] = useState(false)

  const onHide = () => {
    setVisibleInner(false)
  }

  useEffect(() => {
    setVisibleInner(visible > 0)
  }, [ visible ])

  return (
    <div className="dialog" style={ { display: visibleInner ? 'block' : 'none' }}>
      <div className="dialog-mask" onClick={ onHide }></div>
      <div className="dialog-body">
        { title ? <div className="dialog-title">{ title }</div> : null }
        <div className="dialog-main">
          {/* 注意这里,通过children实现默认插槽功能 */}
          {children}
        </div>
        <div className="dialog-footer">
          <div className="button-cancel" onClick={ onHide }>取消</div>
          <div className="button-confirm" onClick={ onHide }>确定</div>
        </div >
      </div >
    </div >
  )
}

slot

import React, { useState, useEffect } from "react"
import Dialog from './components/dialog'

export default function Slot() {
  const [visible, setVisible] = useState(-1)

  const onToggleVisible = () => {
    setVisible(Math.random())
  }

  return (
    <div className="slot">
      <button onClick={ onToggleVisible }>切换dialog</button>
      <Dialog
        visible={visible}
        title="默认插槽"
      >
        {/* 注意这里,会被Dialog组件的children读取并且替换掉 */}
        <div className="slot-body">前端胖头鱼</div>
      </Dialog>
    </div>
  )
}

预览

8e7c3c0711a0e08965a00ab63fb03b51.gif


10. name slot(具名插槽)

当组件内部有多个动态内容需要外部来填充的时候,一个默认插槽已经不够用了,我们需要给插槽取个名字,这样外部才可以”按部就班“到指定位置。

我们来丰富一下Dialog组件,假设title也可以支持动态传递内容呢?

Vue

Vue中通过<slot name="main"></slot>形式先进行插槽的声明,再通过v-slot:main形式进行使用,一个萝卜一个坑也就填起来了

nameSlot源代码点这里

Dialog改造

<template>
  <div class="dialog" v-show="visible">
    <div class="dialog-mask" @click="onHide"></div>
    <div class="dialog-body">
      <div class="dialog-title" v-if="title">{{ title }}</div>
      <!-- 注意这里,没有传title属性,时候通过插槽进行内容承接 -->
      <slot name="title" v-else></slot>
      <div class="dialog-main">
        <!-- 声明main部分 -->
        <slot name="main"></slot>
      </div>
      <div class="dialog-footer">
        <div class="button-cancel" @click="onHide">取消</div>
        <div class="button-confirm" @click="onHide">确定</div>
      </div>
    </div>
  </div>
</template>
// ... 其他地方和上面试一样的

nameSlot

<template>
  <div class="slot">
    <button @click="onToggleVisible">切换dialog</button>
    <Dialog
      :visible.sync="visible"
    >
      <template v-slot:title>
        <div class="dialog-title">具名插槽</div>
      </template>
      <template v-slot:main>
        <div class="slot-body">前端胖头鱼</div>
      </template>
    </Dialog>
  </div>
</template>

<script>
import Dialog from './components/dialog.vue'

export default {
  name: 'nameSlot',
  components: {
    Dialog,
  },
  data () {
    return {
      visible: false
    }
  },
  methods: {
    onToggleVisible () {
      this.visible = !this.visible
    }
  }
}
</script>

React

前面通过props.children属性可以读取组件标签内的内容算是和Vue默认插槽实现了一样的功能,但是具名插槽如何实现呢?React好玩的其中一个点,我觉得是属性啥玩意都可以传、字符串数字函数连DOM也可以传。所以实现具名插槽也很简单,直接当属性传递就可以

nameSlot源代码点这里

Dialog改造

import React, { useState, useEffect } from "react"

import './dialog.css'

export default function Dialog(props) {
  // 原谅我用visible -1这种傻叉的方式先实现了, 重点不是在这里
  const { title, main, visible = -1 } = props
  const [visibleInner, setVisibleInner] = useState(false)

  const onHide = () => {
    setVisibleInner(false)
  }

  useEffect(() => {
    setVisibleInner(visible > 0)
  }, [ visible ])

  return (
    <div className="dialog" style={ { display: visibleInner ? 'block' : 'none' }}>
      <div className="dialog-mask" onClick={ onHide }></div>
      <div className="dialog-body">
        {/* { title ? <div className="dialog-title">{ title }</div> : null } */}
        {/* 注意这里,直接渲染title就可以了 */}
        { title }
        <div className="dialog-main">
          {/* 注意这里,通过children实现默认插槽功能 */}
          {/* {children} */}
          {/* 这一这里不是children了,是main */}
          { main }
        </div>
        <div className="dialog-footer">
          <div className="button-cancel" onClick={ onHide }>取消</div>
          <div className="button-confirm" onClick={ onHide }>确定</div>
        </div >
      </div >
    </div >
  )
}

nameSlot

import React, { useState } from "react"
import Dialog from './components/dialog'

import './slot.css'

export default function NameSlot() {
  const [visible, setVisible] = useState(-1)

  const onToggleVisible = () => {
    setVisible(Math.random())
  }

  return (
    <div className="slot">
      <button onClick={ onToggleVisible }>切换dialog</button>
      <Dialog
        visible={visible}
        // 注意这里,直接传递的DOM
        title={ <div className="dialog-title">默认插槽</div> }
        // 注意这里,直接传递的DOM
        main={ <div className="slot-body">前端胖头鱼</div> }
      >
      </Dialog>
    </div>
  )
}

预览

可以看到具名插槽,React直接用属性反而更简洁一些

31e7d9be0db7ca68f6585b0c21549626.gif
具名插槽.gif

11. scope slot(作用域插槽)

有了默认插槽具名插槽最后当然少不了作用域插槽啦!有时让插槽内容能够访问子组件中才有的数据是很有用的,这也是作用域插槽的意义所在

假设:Dialog组件内部有一个userInfo: { name: '前端胖头鱼' }数据对象,希望使用Dialog组件的外部插槽也能访问到,该怎么做呢?

Vue

scopeSlot源代码点这里

Dialog

<template>
  <div class="dialog" v-show="visible">
    <div class="dialog-mask" @click="onHide"></div>
    <div class="dialog-body">
      <div class="dialog-title" v-if="title">{{ title }}</div>
      <!-- 注意这里,通过绑定userInfo外部可以进行使用 -->
      <slot name="title" :userInfo="userInfo" v-else></slot>
      <div class="dialog-main">
     <!-- 注意这里,通过绑定userInfo外部可以进行使用 -->
        <slot name="main" :userInfo="userInfo"></slot>
      </div>
      <div class="dialog-footer">
        <div class="button-cancel" @click="onHide">取消</div>
        <div class="button-confirm" @click="onHide">确定</div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: "dialog",
  // ...
  data () {
    return {
      userInfo: {
        name: '前端胖头鱼'
      }
    }
  },
  // ... 
};
</script>

scopeSlot

<template>
  <div class="slot">
    <button @click="onToggleVisible">切换dialog</button>
    <Dialog
      :visible.sync="visible"
    >
      <template v-slot:title>
        <div class="dialog-title">作用域插槽</div>
      </template>
      <!-- 注意这里 -->
      <template v-slot:main="{ userInfo }">
        <!-- 注意这里userInfo是Dialog组件内部的数据 -->
        <div class="slot-body">你好{{ userInfo.name }}</div>
      </template>
    </Dialog>
  </div>
</template>

React

还是那句话,React中万物皆可传,类似实现具名插槽中我们直接传递DOM,同样我们也可以传递函数,将Dialog组件内部的userInfo数据通过函数传参的方式给到外部使用

scopeSlot源代码点这里

Dialog改造

import React, { useState, useEffect } from "react"

import './dialog.css'

export default function Dialog(props) {
  // 原谅我用visible -1这种傻叉的方式先实现了, 重点不是在这里
  const { title, main, visible = -1 } = props
  const [visibleInner, setVisibleInner] = useState(false)
  const [ userInfo ] = useState({
    name: '前端胖头鱼'
  })

  const onHide = () => {
    setVisibleInner(false)
  }

  useEffect(() => {
    setVisibleInner(visible > 0)
  }, [ visible ])

  return (
    <div className="dialog" style={ { display: visibleInner ? 'block' : 'none' }}>
      <div className="dialog-mask" onClick={ onHide }></div>
      <div className="dialog-body">
        {/* 作用域插槽,当函数使用,并且把数据传递进去 */}
        { title(userInfo) }
        <div className="dialog-main">
          {/* 作用域插槽,当函数使用,并且把数据传递进去 */}
          { main(userInfo) }
        </div>
        <div className="dialog-footer">
          <div className="button-cancel" onClick={ onHide }>取消</div>
          <div className="button-confirm" onClick={ onHide }>确定</div>
        </div >
      </div >
    </div >
  )
}

scopeSlot

import React, { useState } from "react"
import Dialog from './components/dialog'

import './slot.css'

export default function ScopeSlot() {
  const [visible, setVisible] = useState(-1)

  const onToggleVisible = () => {
    setVisible(Math.random())
  }

  return (
    <div className="slot">
      <button onClick={ onToggleVisible }>切换dialog</button>
      <Dialog
        visible={visible}
  // 通过函数来实现插槽
        title={ () => <div className="dialog-title">作用域插槽</div> }
  // 接收userInfo数据
        main={ (userInfo) => <div className="slot-body">你好{ userInfo.name }</div> }
      >
      </Dialog>
    </div>
  )
}

预览

a097c322bf9fa23c852441aa1d80c5ca.gif
作用域插槽.gif

- END -

d8677455e6486b5dd38084886e48e55f.png

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

23e6e1efa16504e00088cffbcd26eda0.png

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【建议收藏】11+实战技巧,让你轻松从Vue过渡到React 的相关文章

  • JavaScript 重定向到新窗口

    我有以下代码 它根据下拉列表的值重定向到页面 我如何使其在新窗口中打开 function goto form var index form select selectedIndex if form select options index
  • 当 OnFocusChangeListener 应用于包装的 EditText 时,TextInputLayout 没有动画

    不能比标题说得更清楚了 我有一个由文本输入布局包裹的 EditText 我试图在 EditText 失去焦点时触发一个事件 但是 一旦应用了事件侦听器 TextInputLayout 就不再对文本进行动画处理 它只是位于 editText
  • 在requestAnimationFrame中使用clearRect不显示动画

    我正在尝试在 HTML5 画布上做一个简单的 javascript 动画 现在我的画布是分层的 这样当我收到鼠标事件时 背景层不会改变 但带有头像的顶层会移动 如果我使用 requestAnimationFrame 并且不清除屏幕 我会看到
  • 如何将 Google Charts 与 Vue.js 库一起使用?

    我正在尝试使用 Vue js 库使用 Google Charts 制作图表 但我不知道如何添加到 div 这是我尝试做的 这是如何使用普通 javascript 添加图表 这是文档的代码示例 https developers google
  • MVC 在布局代码之前执行视图代码并破坏我的脚本顺序

    我正在尝试将所有 javascript 包含内容移至页面底部 我正在将 MVC 与 Razor 一起使用 我编写了一个辅助方法来注册脚本 它按注册顺序保留脚本 并排除重复的内容 Html RegisterScript scripts som
  • Meteor - 从客户端取消服务器方法

    我正在通过服务器方法执行数据库计数 用户可以选择他们希望如何执行计数 然后调用该方法 我的问题是 计数可能需要一些时间 并且用户可能会在方法运行时改变主意并请求不同的计数 有什么方法可以取消调用的方法并运行新的计数吗 我认为 this un
  • Java 和 Python 可以在同一个应用程序中共存吗?

    我需要一个 Java 实例直接从 Python 实例数据存储中获取数据 我不知道这是否可能 数据存储是否透明 唯一 或者每个实例 如果它们确实可以共存 都有其单独的数据存储 总结一下 Java 应用程序如何从 Python 应用程序的数据存
  • java for windows 中的文件图标叠加

    我正在尝试像 Tortoise SVN 或 Dropbox 一样在文件和文件夹上实现图标叠加 我在网上查了很多资料 但没有找到Java的解决方案 Can anyone help me with this 很抱歉确认您的担忧 但这无法在 Ja
  • 不接受任何内容也不返回任何内容的函数接口[重复]

    这个问题在这里已经有答案了 JDK中是否有一个标准的函数式接口 不接受也不返回任何内容 我找不到一个 像下面这样 FunctionalInterface interface Action void execute 可运行怎么样 Functi
  • HTML 离线应用程序缓存,列出下载的文件

    作为我正在构建的离线 Web 应用程序的加载屏幕的一部分 使用缓存清单 http developer apple com library safari documentation iPhone Conceptual SafariJSData
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • 干净构建 Java 命令行

    我正在使用命令行编译使用 eclipse 编写的项目 如下所示 javac file java 然后运行 java file args here 我将如何运行干净的构建或编译 每当我重新编译时 除非删除所有内容 否则更改不会受到影响 cla
  • 条件在反应本机生产中失败,但在开发中有效

    我创建了一个反应本机应用程序 我需要通过它进行比较 如果属实 就会执行死刑 问题是 该条件适用于 React Native 开发模式 而不适用于 React Native 生产版本 我使用 firebase 作为数据库 也使用 redux
  • 如何更改此 jquery 插件的时区/时间戳?

    我正在使用这个名为 timeago 的插件 在这里找到 timeago yarp com 它工作得很好 只是它在似乎不同的时区运行 我住在美国东部 费城时区 当我将准确的 EST 时间放入 timeago 插件时 比如 2011 05 28
  • 包 javax.el 不存在

    我正在使用 jre6 eclipse 并导入 javax el 错误 包 javax el 不存在 javac 导入 javax el 过来 这不应该是java的一部分吗 谁能告诉我为什么会这样 谢谢 米 EL 统一表达语言 是 Java
  • JQuery 图像上传不适用于未来的活动

    我希望我的用户可以通过帖子上传图像 因此 每个回复表单都有一个上传表单 用户可以通过单击上传按钮上传图像 然后单击提交来提交帖子 现在我的上传表单可以上传第一个回复的图像 但第二个回复的上传不起作用 我的提交过程 Ajax 在 php 提交
  • 为什么 jquery 没有检测到单选按钮未被选中的情况? [复制]

    这个问题在这里已经有答案了 可能的重复 JQuery radioButton change 在取消选择期间不会触发 https stackoverflow com questions 5176803 jquery radiobutton c
  • 使用 CXF-RS 组件时,为什么我们使用 而不是普通的

    作为后续这个问题 https stackoverflow com questions 20598199 对于如何正确使用CXF RS组件我还是有点困惑 我很困惑为什么我们需要
  • 如何防止在Spring Boot单元测试中执行import.sql

    我的类路径中有一个 import sql 文件 其中包含一些 INSERT 语句 当使用 profile devel 运行我的应用程序时 它的数据被加载到 postgres 数据库中 到目前为止一切正常 当使用测试配置文件执行测试时 imp
  • fullCalendar 未显示正确的结束日期

    我正在看调试页面 http jsbin com wukofacaxu edit js outputFullCalendar 官方网站的 我想安排一个活动时间为 22 09 2015 至 30 09 2015 dd mm yyyy 但它只显示

随机推荐

  • Python+Vue计算机毕业设计银行助学贷款管理系统0o571(源码+程序+LW+部署)

    该项目含有源码 文档 程序 数据库 配套开发软件 软件安装教程 项目运行环境配置 Python3 7 7 Django Mysql5 7 pip list HBuilderX Vscode也行 Vue Pychram社区版 项目技术 Dja
  • Python Pandas 图形绘制(一):折线图,柱状图

    Pandas 图形绘制 一 折线图 柱状图 一 折线图 Line Chart 1 1 默认绘制折线图 df plot 1 2 绘制多条折线 二 柱状图 Bar Chart 2 1 垂直柱状图 df plot bar 2 2 叠加柱状图 st
  • 安全测试-优秀测试工程师必备的4项安全测试方法!

    用您5分钟时间阅读完 希望能对您有帮助 一 安全性测试 1 安全性测试方法 测试手段可以进行安全性测试 目前主要安全测试方法有 1 静态的代码安全测试 主要通过对源代码进行安全扫描 根据程序中数据流 控制流 语义等信息与其特有软件安全规则库
  • Couldn‘tparse bundle asset‘“D: \vue\cy_ gw2\dist\js \chunk- vendors.js1Analyzerwi 11usemodule

    报错信息 Couldn tparse bundle asset D vue cy gw2 dist js chunk vendors js1Analyzerwi 11usemodule 报错截图 报错原因 未安装less和less load
  • 从React源码来学hooks是不是更香呢

    本文将讲解 hooks 的执行过程以及常用的 hooks 的源码 hooks 相关数据结构 要理解 hooks 的执行过程 首先想要大家对 hooks 相关的数据结构有所了解 便于后面大家顺畅地阅读代码 Hook 每一个 hooks 方法都
  • 2D平面上的二连杆机器臂反向运动模拟(matlab代码示例)

    2D平面上的二连杆机器臂反向运动模拟 matlab上先下载 robotics system toolbox工具箱 robot rigidBodyTree DataFormat column MaxNumBodies 3 L1 1 the l
  • opencv+python物体检测【03-模仿学习】

    仿照练习 原文链接 步骤一 准备图片 正样本集 正样本集为包含 识别物体 的灰度图 一般大于等于2000张 尺寸不能太大 尺寸太大会导致训练时间过长 负样本集 负样本集为不含 识别物体 的任何图片 一般大于等于5000张 尺寸比正样本集稍大
  • Egg 使用 Sequelize

    npm install save egg sequelize mysql2 在 config plugin js 中引入 egg sequelize 插件 exports sequelize enable true package egg
  • 人工智能与教育融合的文献总结

    一般来说 人工智能与教育融合 首先要重塑教育理念 这是实现 教育 人工智能 的前提 格物斯坦提示 越是科技发达 越需要人性的支撑 教育的本质也是一种能力 生命和智能反映的是个体能力 这是亘古不变的科学原理 人工智能的观点来源于人们对于人工计
  • 数字型字符串千分位加逗号

    在数字型字符串千分位加逗号 param str return public static String addComma String str boolean neg false if str startsWith 处理负数 str str
  • 回调函数(入门篇)

    首先 我们回忆一下 标准库函数printf是如何被我们调用的 1 包含库函数所在的头文件 include
  • Linux sed 利剑之探索

    sed Linux sed命令是利用script来处理文本文件 sed可依照script的指令 来处理 编辑文本文件 Sed主要用来自动编辑一个或多个文件 简化对文件的反复操作 编写转换程序等 语法 sed hnV e
  • Linux防火墙开关命令

    关闭防火墙 systemctl stop firewalld service 停止firewall systemctl disable firewalld service 禁止firewall开机启动 开启端口 firewall cmd z
  • LeetCode算法题 :第三大的数thirdMax

    给定一个非空数组 返回此数组中第三大的数 如果不存在 则返回数组中最大的数 要求算法时间复杂度必须是O n 示例 1 输入 3 2 1 输出 1 解释 第三大的数是 1 示例 2 输入 1 2 输出 2 解释 第三大的数不存在 所以返回最大
  • 区块链笔记4--BTC实现

    1 UTXO 区块链是一个去中心化的账本 比特币采用了 基于交易的账本模式 然而 系统中并无显示记录账户包含BTC数 实际上其需要通过交易记录进行推算 在比特币系统中 全节点需要维护一个名为 UTXO UnspentTransaction
  • Android技术功底不够如何去面试,已整理成文档

    IT行业的前景 近几年来 大数据 人工智能AI 物联网等一些技术不断发展 也让人们看到了IT行业的繁荣与良好的前景 越来越多的高校学府加大了对计算机的投入 设立相应的热门专业来吸引招生 当然也有越来越多的人选择从事这个行业 希望能从这个行业
  • 线性回归介绍及分别使用最小二乘法和梯度下降法对线性回归C++实现

    回归 在这类任务中 计算机程序需要对给定输入预测数值 为了解决这个任务 学习算法需要输出函数f Rn R 除了返回结果的形式不一样外 这类问题和分类问题是很像的 这类任务的一个示例是预测投保人的索赔金额 用于设置保险费 或者预测证券未来的价
  • 进入U盘PE系统无法识别硬盘分区的原因分析和解决方法

    进入U盘PE系统无法识别硬盘分区的原因分析和解决方法 时间 2015 07 15 来源 http www xitongtiandi com 复制网址 进入U盘PE系统无法识别硬盘分区的原因分析和解决方法分享给大家 PE Windows PE
  • Sqli-labs靶场详细攻略Less 23-28a

    Less 23 28a Less 23 GET Error based strip comments 这一关还是使用get方法进行注入 不过这次对 这些用于注释的字符做了过滤 这样我们可以使用两个 进行绕过 第一个 用于闭合原代码语句中的前
  • 【建议收藏】11+实战技巧,让你轻松从Vue过渡到React

    前言 在这个卷神辈出的时代 只是熟练Vue的胖头鱼 已经被毒打过多次了 面试中曾被质疑 你居然不会React 我无语凝噎 不知说啥是好 这篇文章尝试将Vue中一些常见的功能在React中实现一遍 如果你恰巧是Vue转React 或者Reac