【react框架】组件之间的信息传递都有哪些方式?帮你归纳

父向子

props属性

具体可看【react框架】学习记录5-组件实例的三大属性state、props、refs

context链式传递

功能和vue的provide/inject一样的,且类组件和函数组件的用法是差不多的。

首先创建一个负责传递数据的状态组件Content.jsx:

import React from 'react';

const Content = React.createContext(); // 引入API,类似定义了一个空组件

export default Content; 

然后在父组件中去使用这个状态组件:

import Content from './Content.jsx'

let username = 'xiaoming'
let age = 12

// 模板中把子组件包裹起来,并传入需要传递的变量,可以以对象的形式
<Content.Provider value={{ username, age }}> 
    <Zizujian />
</Content.Provider>

当然,如果你想把状态维护在一个组件中也可以,上面两个合成一个文件写即可:

export const Content = React.createContext(); // 引入API,类似定义了一个空组件

let user = {
	name: 'xxx',
	age: 12
}

// 模板中把子组件包裹起来,并传入需要传递的变量,可以以对象的形式
<Content.Provider value={user}> 
	<button>点击修改userName</button>
    <Zizujian />
</Content.Provider>

然后在子组件中就可以接收传进来的东西了,类组件可以这样写:

import Content from './Content.jsx' // 注意,引入的是状态组件而不是父件

export default class Zizujian extends Component {
	static contextType = Content;
	render() {
		const { name, age } = this.context // 获取到数据
		return (
			<div></div>
		)
	}
}

在函数式子组件中可以这样使用:

import Content from './Content.jsx' // 注意,引入的是状态组件而不是父件

export default function Zizujian() {
  return (
    <div>
      <Content.Consumer> // 改用这个获取,因为函数式组件没有this,不能const {username,age} = this.context
        {(value) => { // 用函数接收数据
          return `${value.name}, 年龄是${value.age}`;
        }}
      </Content.Consumer>
    </div>
  );
}

// 或者使用hooks
import Content from './Content.jsx' // 注意,引入的是状态组件而不是父件

export default function Zizujian() {
	const userInfo = useContext(Content) // 这样就能拿到数据了
	return (
	  <div></div>
	);
}

和vue一样,实际开发不会使用这个

render插槽

功能和vue的solt插槽一样。先来看看普通的插槽怎么写:

// 在父组件中,同时写a和b组件
<A>
  <B>xxxx</B> // 插入了b组件
</A>

// 在a组件中
<div>
    {this.props.children} // 这样去渲染出来插入的标签
</div>

问题来了,这样子如果a想传数据给b组件,比较麻烦,所以react提供了render props:

// 在父组件中,同时写a和b组件
<A render={(data) => <B data={data}></B>}></A> // render可以自定义命名,入参是传入的值,返回的是一个插入的标签

// 在a组件中
<div>
    {this.props.render(内部state数据)} // 这样去渲染出来插入的标签
</div>

// 在b组件中
this.props.data // 那到a传入的值

子向父

调用父级函数

父级首先通过props给子级传递一个函数:

updateApp = (info)=>{
	console.log('拿到子级传过来的信息', info)
}

render() {
	return (
			<Zizujian updateAppState={this.updateApp}/>
	)
}

子级在自己内部接收这个props传来的函数,需要传递信息的时候调用并且把信息作为入参传入即可。


兄弟/子孙之间

redux(推荐)

我记录了一篇博客

useReducer与useContext(别用了)

函数组件的原生hook,是官方参照redux出的简化版,可以看看使用方式

个人认为当你需要使用到状态管理的时候,就不需要考虑这个了,直接上redux或者相关库,因为有可能后面随着业务的复杂度上升,状态管理的要求也会更多。

第三方库

pubsubJS 发布订阅(可考虑)

先安装这个库

yarn add pubsub-js

在A组件中订阅消息(接受消息):

import PubSub from 'pubsub-js' // 先引入

componentDidMount(){
    // 订阅了一个叫做fn的消息
	this.token = PubSub.subscribe('fn',(_, stateObj)=>{ // 回调默认传入两个参数,第一个是发布描述(不想要可以用_代替),第二个是发布的数据
		this.setState(stateObj)
	})
}

componentWillUnmount(){
	PubSub.unsubscribe(this.token) // 记得要销毁订阅
}

在B组件中发布消息:

// 可在不同地方发布多个不同数据的消息
PubSub.publish('fn',{ a : 1 })

PubSub.publish('fn',{ b : 1 })

PubSub.publish('fn',{ c : 1 })

这个库不要太过分依赖,当页面到处都是异步操作的时候,就难控制了。

think-react-store 状态管理

找不到官方的文档地址,先暂时贴出npm地址和源码地址吧:

npm:https://www.npmjs.com/package/think-react-store
github:https://github.com/cpagejs/think-react-store

其实是一个简化版的redux,这个库非常轻量,使用也很简单。这里简单记录一下使用方式(安装就不记录了)。

可以先分模块,例如用户模块store/user.js:

export default {
  state: {
    id: undefined,
    username: undefined
  },
  reducers: { // 同步操作
    getUser(state, payload) {
      return { // 返回一个对象,自动合并state
        ...state,
        ...payload
      }
    }
  },
  effects: { // 异步操作
    async getUserAsync(dispatch, rootState, payload){
      await new Promise(resolve => {
        setTimeout(() => {
          resolve();
        }, 1000);
      });
      dispatch({
        type: 'getUser',
        payload
      });
    }
  }
};

然后创建个汇总根文件store/index.js

export { default as user } from './user';

在父组件中使用:

import React, { useState } from 'react';
import { StoreProvider } from 'think-react-store';
import * as store from './stores'; 
import log from 'think-react-store/middlewares/log'; // 引入个中间件,就理解为引入个功能(这个中间件的功能就是自动打印出store的变化,供开发者调试)
import User from './user'; // 子组件

export default function(props){
  const [state, setState] = useState()

  return (
    <StoreProvider store={store} middleware={[log]}> // 一定要包裹起来,传入所有store,中间件(不需要可不写)
      <User />
    </StoreProvider>
  )
}

子组件中使用:

import React, { useState, useEffect } from 'react';
import { useStoreHook, useStateHook, useDispatchHook } from 'think-react-store';

export default function(props){
  const [state, setState] = useState()
  const { user: { id, username, getUserAsync } } = useStoreHook(); // 方法一,拿user模块里的东西
  const states = useStateHook('user'); // 方法二,直接拿user模块里的state
  // console.log(states)
  const dispatchs = useDispatchHook(); // 获取派发hooks

  useEffect(() => {
    getUserAsync({ // 方法一的使用方式
      id: 10, 
      username: 'admin'
    });
  }, [])

  const handleClick = () => {
    dispatchs({ // 方法二的派发使用方式
      key: 'user',
      type: 'getUserAsync',
      payload: {
        id: 20,
        username: 'admin2'
      }
    });
  };



  return (
    <div>
      user-id: {id}
      <br/>
      username: {username}
      <br/>
      <button onClick={handleClick}>修改</button>
    </div>
  )
}

dva 状态管理

也是个redux简化版,官方地址https://dvajs.com/。umi二次框架默认指定安装了这个。

这里也简单记录一下使用方式。

模板src/models/test.js:

import { getLists } from '@/api/search' 
export default {
  namespace: 'test', // 没有该属性就会自动取文件名
  state: {
    text: 'dva',
    lists: []
  },
  // 同步
  reducers: {
    getLists(state, action){ // 第一个为默认state传入,第二个为调用该方法传入的参数
      return {
        ...state,
        lists: action.payload
      }
    }
  },
  // 异步
  effects: {
    *getListsAsync({payload}, {call, put}){ // call为异步操作,put为同步派发
      const res = yield call(getLists, payload); // call传入异步函数,以及异步函数里的参数,以await的形式返回结果
      yield put({
        type: 'getLists',
        payload: res.lists
      })
    }
  }
}

在父级组件中使用:

import { connect } from 'dva';


class DvaDemo extends Component { // 需要中间层包裹
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
      </div>
    )
  }
}

export default connect(({test})=>({ // 要哪个models文件,就存入对应文件名
  test
}))(DvaDemo)

在子级组件中使用

mport React, { Component } from 'react';

export default class Lists extends Component {

  constructor(props) {
    super(props);
  }

  render() {
    const { lists: {text, data} } = this.props; // 获取state
    this.props.dispatch({ // 执行同步
      type: 'test/getLists', // 第一个为namespace的属性值
      payload: '参数'
    })
    this.props.dispatch({ // 执行异步
      type: 'test/getDataAsync',
      payload: '参数'
    })
    return (
      <div>
      </div>
    )
  }
}

MobX(网上最推荐)

这是网上最推荐的redux替代方案,官方地址:https://zh.mobx.js.org/installation.html

这个库的写法完全和redux不一样,而且他是可以通过直接修改state来改变其值的,和vuex很像。大家都认为它是未来,现在差就差在生态没redux那么丰富。

建议如果项目是很老的版本,已经难以升级,又不想用老版的redux,可以试试这个。

12-15~17


未来会持续补充…

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值