react传值(父子传值,context传值,redux传值)

总述:

        组件间通讯有什么方法:
             1) 使用props传值 
             2) 使用context传值( Provider和 Consumer
             3) 使用redux传值

        非跨组件传参,以上传参方式都可用,比较常用也好用的是父子props传参;

        跨组件传参,使用props一层层往下传,使用context,或者用redux 。

和vue的传参类比学习,套路相似,略有差别,对比着学习更易懂,可以一起看Vue传值(父子传值,provide/inject传值,vuex传值)

一、父子组件传参(传值、传方法)


1.  父 --->子

父组件:

<Child    
     定义个属性1 = { this.state.值 };
     定义个属性2 = { this.方法名 };
/ >

方法名=( )=>{  }

子组件:

值:this.props.属性1
方法:this.props.属性2( )

2. 子 --->父

一句话可以概括,父组件向子组件传递属性值,子组件去触发父组件方法。
子组件不能直接修改父组件的值,遵从单项数据流思想,只能子组件通知父组件自己去进行增删改查。

传值:

 父组件:

<Child   
     定义个属性2 = { this.方法名 }   
/ >

方法名=()=> {
     // 获取的子组件的参数存在自己组件的state里
}

 子组件:

this.props.属性2(子组件的参数) 

 传方法:

说在实现方式前面的话:

  • function
    • 对于用function定义的组件是没有办法用ref获取的,原因是: ref回调函数会在组件被挂载之后将组件实例传递给函数。但是使用function定义的函数并没有实例。
    • 但是仍然可以获取function定义的组件中的DOM元素
  • class
    • 用class定义的组件由于可以获取组件实例,因此ref函数会在组件挂载的时候将实例传递给组件

将ref回调函数作用于某一个React组件,此时回调函数会在当前组件被实例化并挂载到页面上才会被调用。

ref回调函数被调用时,会将当前组件的实例作为参数传递给函数。


下面是类组件的实现方式:

1)组件没有使用redux时, 需要给子组件属性添加onRef={(ref)=>{ this.child = ref }},添加ref属性可以获取子组件的所有信息。

子组件:

// 在组件完成挂载后,去把this传给父

componentDidMount(){
     this.props.onRef(this);
}
myName=()=>{
  console.log('哈哈哈,我可以被父组件调用了,耶!');
}

父组件:

  <Child onRef={(ref)=>{ this.child = ref}} />
  <button onClick={this.click} >click</button>
 click = (e) => {
        this.child.myName()
 }

2)组件使用了redux时,redux属于高阶组件,他会包裹住我们的子组件,导致ref无法获取,那就需要在连接器的参数上设置一下,把withRef打开。而父组件在调用子方法的时候,也需要使用getWrappedInstance获取。

子组件:

export default connect(stateToProps, null, null, { withRef: true }) (Child);

父组件:

onClick = () => {
    this.Child.getWrappedInstance.myName();
} 

二、跨组件传参

1. 使用props一层层往下传(繁琐,不好用,有时也用)
2. 使用context
3. 使用redux

1. 使用 context 的3种情况:

  • React.createContext提供的 Provider和 Consumer (推荐使用)
  • 函数组件:React.createContext提供的 Provider和 useContext钩子
  • Class组件:React.createContext提供的 Providerclass的 contextType属性

以下是父组件使用Provider生产数据,子孙组件使用Consumer消费数据:

父组件 ( MyContext.Provider):

import React, { createContext } from "react";

//light是默认值,当Consumer向上都找不到对应的provide时显示
const  MyContext = createContext({name:'light'}); 

export default function App() {
  return (
    //Provider组件接收一个value属性,此处传入一个带有name属性的对象
    <MyContext.Provider value={{ name: `context's value is string!` }}>
      {/*这里写后面要进行包裹的子组件,此处先行导入后续需要消费context的组件*/}
      <Children/>
    </MyContext.Provider>
  );
}

子组件、子孙组件( MyContext.Consumer) : 

import React, { useReducer } from "react";
const  MyContext = createContext();
const Children= () => {
  return ( 
    <MyContext.Consumer>
      {(value) => {
        return (
          <div>
            使用Context方式获取的值:{JSON.stringify(value)}
          </div>
        );
      }}
    </MyContext.Consumer>
  );
};
 
export default Children;

2. 使用 redux

1) 安装react-redux插件

npm install --save react-redux

2) 在根组件里注入store (index.jsx)

import ReactDOM from 'react-dom';
import React from 'react';
import App from './App';
import { Provider } from 'react-redux'
import store from './store';
 
ReactDOM.render(
    // 提供store仓库给所有的组件,利用Provider将祖先组件包裹起来
    // 通过Provider的store属性将Redux的store传递给Provider,那么就可以在所有后代中直接使用Redux了
    <Provider store={store}>
        <App/>
    </Provider>
    , document.getElementById('root'));

3)reducer给store设置数据 (store.js)

注:store仓库本身是没有数据的,所以需要有reducer给它设置数据,需要与store进行结合

import { createStore } from 'redux';
import reducer from '../reducers';
const store = createStore(calculate);

export default store;

4) 定义action(action.js)

const ADD_MODAL = 'ADD_MODAL';
const DEL_MODAL = 'DEL_MODAL';
const GETlISTS='GETlISTS';
const SHOWLOADING='SHOWLOADING';
 
export const add = item => dispatch => {
    dispatch({
        type: ADD_MODAL,
        payload: item
    })
}
 
export const del = item => dispatch => {
    dispatch({
        type: ADD_MODAL,
        payload: item
    })
}
export const getListData = (payload) => {
	return {
		type: 'GETlISTS',
		payload,
	};
};

export const showLoading = (payload) => {
	return {
		type: 'SHOWLOADING',
		payload,
	};
};

5)reducers实现state数据变化 (reducers.js)

注:具体的操作执行交由reducer完成(reducer是数据的处理中心,数据的初始化,修改都在reducer中完成)

/**
 * 函数reducer,它负责根据需求去修改state里面的值,也可指定初始化值
 * 接收两个参数state 和action ,state可以取出里面要修改的值 
 */

import { ADD_MODAL, DEL_MODAL } from '../action'
 
const initState = 0
 
const calculate = (state = initState, action) => {
    
    //根据type决定如何加工数据
    switch (action.type) {
        case ADD_MODAL:
           return {...state,modal:true}
        case DEL_MODAL :
            return {...state,modal:false}
        default:
            return state
    }
}

     
export default calculate

5)  或调接口,直接存在redux里 (middle.jsx)

import {getListData,showLoading} from './action';

export function fetchList() {
	return (dispatch) => {
        //数据没有请求前改变loading的state状态值
		dispatch(showLoading(true));
		let url = 'https://api/posts';
		fetch(url)
			.then((res) => {
				return res.json();
			})
			.then((data) => {
				dispatch(getListData(data));
				dispatch(showLoading(false));
			});
	};
}

6) 在需要使用的组件中进行引入{connect}, 以及在页面中使用  (demo.jsx)

import React, { Component } from 'react';
import { connect } from "react-redux";
import { add,del,fetchList} from './actions/count';

class demo extends Component {
    constructor(props) {
        super(props)
        this.state = {
            modals:true;
        }
    }
    const {modal,add,del,fetchList,loading}= this.props;

    render() {
        return (
            <div>
                <h1>页面</h1>
                <div>{modals}</div>
			    <button onClick={() =>{add()}}>
                    增加
                </button>
                <button onClick={() =>{del()}}>
                    减少
                </button>
                
               {loading? <button onClick={fetchList}>获取数据</button>:null}
            </div>
        )
    }
}

/*reducer的state是无法实现数据传递的,因为它是状态,但是,它又需要与组件进行沟通,所以需要将state转成props才能进行属性传递,通过mapStateToProps转化*/
const mapStateToProps = (state) => ({
    modals:state.modal,
    loading: state.loading,
})

/*事件就是动作,动作就是函数,可以定义一个mapDispatchToProps,因为事件是无法进行传递的,唯一能够传递的内容只有属性props, mapDispatchToProps只做派发操作,不做具体动作执行*/
const mapDispatchToProps = (dispatch) => {
    return {
        add(data){ dispatch(add(data)); },
        del(data){ dispatch(del(data)); },
        fetchList,
    }
}

//props属性与组件之间还没有建立起联系,所以需要利用connect进行关联
export default connect(mapStateToProps,mapDispatchToProps )(demo)

参考资料:

https://www.jianshu.com/p/e74202ec3127

https://juejin.cn/post/6924506511511126029

React的contextType的使用方法简介 - 溢杨年华 - 博客园

React Context用法整理(附完整代码)_成续源的博客-CSDN博客_reactcontext用法

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值