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 函数可以自定义 控制台的提示信息
- props的值为数组,数组的元素的 自定义的属性名
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,return,react,props,组件,redux,传值,属性 来源: https://www.cnblogs.com/welcometoxixi/p/16383175.html