Javascript

vue和react的组件传值

本文主要是介绍vue和react的组件传值,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

vue组件传值

1. 父组件给子组件传值

  • 父组件给子组件传值的地方,添加自定义的属性,属性的值就是需要传递给子组件的值,如果属性的值为变量,boolean类型,number类型,对象,数组,null,undefined,需要使用绑定属性
<!-- 父组件中使用子组件 -->
<!-- n和list是一个自定义属性 后面的num和list是父组件的data数据 -->
<child-1 :n="num" :list="list"></child-1>

<!-- 子组件在default中用prop接受数据 -->
props:["n","list"], //接受父组件传递过来的数据的一个自定义属性
  • 在子组件定义的地方,添加props选项

  • props选项有三种写法:

    • props的值为数组,数组的元素的 自定义的属性名 props: ['num']
    • props的值为对象,对象的key值自定义的属性名,value值为数据类型 props: { num: Number }
    • props的值为对象,对象的key值为自定义的属性名,value值为一个对象:该对象的可以有 type、default、required、validator 这些key值
      • type代表数据类型
      • default代表自定义属性的默认值,如果默认值为对象和数组,写为函数返回对象和数组
      • required代表该属性是必须传递的
      • validator 函数可以自定义 控制台的提示信息

2. 子组件给父组件传值

  • 子组件中用 this.$emit 调用 父组件的 自定义事件 并传递数据给父组件, 父组件从自定义事件的方法中获取数据并执行事件
<!-- 父组件中使用子组件 -->
<!-- 通过自定义的事件利用方法获取到子组件的数据 -->
<Child2 @abcd="setUsername"></Child2>
并在default中定义方法
    methods:{
        setUsername(value){
            this.username = value;
        }
    }

<!-- 子组件中使用this.$emit调用事件abcd传递数据this.uesername -->
<button @click="fn">将数据传给父组件</button>
methods:{
	fn(){
		this.$emit("abcd",this.username);
	}
}

3. 子传子(非父子组件传值)

利用公共父组件

需求: 将 child1 更新或改变的数据传递给同级的 child2接受

思路: 利用公共的父元素

步骤: 先实现子传父(利用自定义事件) => 再父传子(利用)

中央事件总线bus传值
const bus = new Vue()

// 接受数据
bus.$on('my-event', (val) => {
  // val 即为接收的数据 1000
})

// 传递数据
bus.$emit('my-event', 1000)

4. 跨层级

  • 方法一: 从父元素prop一层层的传递

  • 方法二: 在main.js中利用vue.prototype放到vue原型上全局使用 (适合每一个页面都需要的数据)

  • 方法三:

    在父组件中用 provide(){return{}} 传递 (如果要传递变量就写成函数的形式)

    在子组件中用 inject:[ ] 接收数据

provide 和 inject

  这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,
  不论组件层次有多深,并在起上下游关系成立的时间里始终生效。
  provide 和 inject 绑定并不是可响应的。这是刻意为之的。
  然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。

{
	data () { return { msg: 'hello world'} },
    provide: { // ✅
      str: 'hi'
    }
  // provide: {// ❌
  //   str: this.msg 
  // }
  provide () { // ✅
    return {
      str: this.msg
    }
  }
}

{inject: ['str']}

5. 子组件直接获取父组件的实例

子组件直接通过 $parent 可以获取到父组件的实例

6. 父组件直接获取子组件的实例

父组件调用子组件时添加 ref 属性, 通过 this.$refs 获取到子组件的实例

7. 全局数据管理

  • 使用条件: 多个视图依赖于同一个状态, 来自不同视图的行为需要变更同一个状态
  • Vuex 的状态存储是响应式的。改变 store 中的状态的唯一途径就是显式地提交mutation
  • 单一状态树即单一数据源,在一个项目中只使用一个store对象,来存储所有共享的状态信息。
//vuex的五个核心概念:
state: {},   数据源(保存全局数据)
getters: {},   计算属性(将store中的数据加工后输出)
actions: {},   异步方法(异步操作必需放到Action中,但只能通过触发同步方法更新数据)
mutations: {},  同步方法(保存更改数据的回调函数,不能包含异步操作)
modules: {   模块(让代码更好维护,数据分类更明确)
	moduleA: {
		namespaced: true, //开启命名空间
		state: {},
    actions: {},
    mutations: {},
	},
	moduleB: {
		namespaced: true,
		state: {},
    actions: {},
    mutations: { 
    	[常量](){} //可以使用常量代替Mutation事件类型
    },
	}
}
# 数据在页面中的使用和更新
---
## 访问state中数据
1. this.$store.state.全局数据名称 (在页面中直接使用/计算属性)
2. mapState映射为计算属性 : 通过导入的`mapState函数`将当前组件需要的全局数据, 映射为当前组件的computed计算属性,在页面中直接使用
computed:{
  ...mapState(['count']) //利用展开运算符将全局数据映射为当前组件的计算属性
}

## 访问getters计算属性
1. $store.getters.名称 访问
2. mapGetters 映射为计算属性
computed:{
	...mapGetters(['showNum'])
}

## 调用Mutation中的方法
1. this.$store.commit() 触发 mutations
2. MapMutations 映射为方法

## 调用Action中的方法
1. this.$store.dispatch 触发 Actions
2. mapActions 映射为方法

computed: {
	...mapState(),
	...mapGetters()
},
methods: {
	...mapActions({ fn: 'user/fn' })
	...mapMutations({ change: 'user/change'})
}

react组件传值

1. 父组件给子组件传值

父组件给子组件传值的地方,添加自定义的属性,属性的值就是需要传递给子组件的值,如果属性的值为变量,boolean类型,number类型,对象,数组,null,undefined,函数,需要使用 {} 包裹

<my-com num={1000} fn={fn}></mycom>

在子组件中通过 this.props 或者 props获取父组件传递的数据

可以使用 prop-types 校验数据

2. 子组件给父组件传值

子组件给父组件传值实际上还是 父组件给子组件传值,只不过父传给子的是一个 函数,该函数由父组件定义(实现),该函数的默认值即为子组件需要传给父组件的值

const getData = (val) => {
	console.log(val) // 子传给父的
}

<my-com fn={getData}></mycom>

在子组件的某一个事件内部,通过 this.props.fn(参数) 或者 props.fn(参数) 完成传值

3. 非父子组件传值

react没有

4. 跨层级

1) 创建Context容器对象:
const XxxContext = React.createContext()  

2) 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:
<xxxContext.Provider value={数据}>
  子组件
</xxxContext.Provider>

3) 后代组件读取数据:

//第一种方式:仅适用于类组件 
static contextType = xxxContext  // 声明接收context
this.context // 读取context中的value数据

//第二种方式: 函数组件与类组件都可以
<xxxContext.Consumer>
  {
  value => ( // value就是context中的value数据
  要显示的内容
  )
}
  </xxxContext.Consumer>
// 类组件 contextType
class Com extends Component {
	static contextType = ColorContext
  render () {
    return (
    	<div>{ this.context }</div> 
    )
  }
}
//类组件 Context.Consumer
class Com extends Component { 
  render () {
    return (
    	<div>
      	<ColorContext.Consumer>
      	{
          (val) => {
      			return <div>{val}</div>
    			}
        }
      	</ColorContext.Consumer>
      </div> 
    )
  }
}
 
// 函数式组件  Context.Consumer
const App = () => {
  return (
  	<div>
      	<ColorContext.Consumer>
      	{
          (val) => {
      			return <div>{val}</div>
    			}
        }
      	</ColorContext.Consumer>
      </div> 
	)
}
// 函数式组件 useContext
const App = () => { // 推荐
  const color = useContext(ColorContext)
  return (
  	<div>{color}</div>
  )
}

// 如果使用开发者工具,发现多Context传值,指示不明确,使用 dispalyName
const ColorContext = React.createContext()
ColorContext.displayName = 'ColorContext'

5. 父组件获取子组件的实例

  • 如果子组件时类组件,可以在调用子组件时,添加ref属性,从而获取子组件的实例

  • 如果时函数式组件,添加的ref 获取不到子组件的实例,因为函数没有实例, 解决方案:

    • useImperativeHandle(ref, createHandle, [deps])
    • 可以让你在使用 ref 时自定义暴露给父组件的实例值
    • useImperativeHandle需要和forwardRef一起使用
    • 不能在函数式组件上直接使用ref属性,因为他们没有实例。
——————————————————————————————————子组件———————————————————————
import React, { useRef, forwardRef, useImperativeHandle } from 'react'

function Child4(props, ref) {
  let userageInput = useRef()
  useImperativeHandle(ref, () => ({
    getUserage: () => {
      return userageInput.current.value
    }
  }))
  return (
    <div>age:
      <input type="text" ref={userageInput}></input>
    </div>
  )
}
export default forwardRef(Child4)
//如果不使用forwardRef: Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

————————————————————————————父组件————————————————————————————
import React, { useRef } from 'react'
import Child4 from '../component/Child4'
export default function UseRef() {
  let usernameInput = useRef()
  let child4 = useRef() //给组件Child4声明一个唯一的名字
  return (
    <div>UseRef
      <div>name
        <input type="text" ref={usernameInput}></input>
        <button onClick={() => {
            console.log("name:", usernameInput.current.value);
          }}>取到input中的值</button>
      </div>
      <Child4 ref={child4}></Child4>
      <button onClick={() => {
          console.log("age:", child4.current.getUserage());
        }}>取到子组件中input中的值</button>
    </div>
  )
}

6. 全局管理(状态管理器)

多个视图依赖于同一个状态, 来自不同视图的行为需要变更同一个状态

react的状态管理器由多种, 都有各自的特性, react项目中常用的状态管理模式有

  • redux ---> 属于js的状态管理模式

  • redux + react-redux

    组件 --分为--> (容器组件 + 展示组件/UI组件)

    核心: connect(mapStateToProps, mapDispatchToProps)(Com)

  • redux + react-redux + redux-thunk ✅✅

    connect(mapStateToProps, mapDispatchToProps)(Com)

    actionCreator 传参

    const aciton = {
    	getList (dispatch) {
    		getProList().then(res => {
       dispatch(action)
     })
    },
    getParamsList (params) {
     return (dispatch) => {
       getProList(params).then(res => {
         dispatch(action)
       })
      }
     }
    }
    

    mapDispatchToProps

    import aciton from '****'
    (dispatch) => {
    	return {
     getListData () {
       dispatch(action.getList)
     },
     getParamsListData () {
       dispatch(action.getParamsList({ count: 1}))
     }
    }
    }
    
  • Redux + react-redux + redux-saga ✅

    核心点:

    import { call, put, takeLatest } from "redux-saga/effects";
    import { getProList } from '../api/pro' //导入请求getProList的api
    import * as types from './../store/type'
    
    //saga是在generator中处理异步操作
    function * getProListAction (params: any): any {
      const res = yield call(getProList, params.payload) //call请求数据
      yield put({   //更新数据
        type: types.CHANGE_PRO_LIST,
        payload: res.data.data
      })
    }
    
    function * mySaga () {
      // 当用户一旦选中 key 值,自动执行value的函数
      // 此处触发上面的generator函数 (而组件中需要去触发types.REQUEST_PRO_LIST)
      yield takeLatest(types.REQUEST_PRO_LIST, getProListAction)
    }
    
    export default mySaga
    
    import { createStore, applyMiddleware } from 'redux'
    import { combineReducers } from 'redux-immutable'
    import createSagaMiddleware from 'redux-saga' // 引入saga
    
    import { menu, pro } from './reducers'
    import mySaga from './mySaga'
    
    const reducer = combineReducers({
      menu, pro
    })
    
    const middleware = createSagaMiddleware() //生成saga中间件
    const store = createStore(reducer, applyMiddleware(middleware))
    middleware.run(mySaga) // 使saga中的异步操作生效
    
    export default store
    
  • Redux + redux-thunk

  • Redux + redux-saga

  • mobx + mobx-react ✅✅

  • dva.js

  • Umi.js ✅✅

这篇关于vue和react的组件传值的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!