react组件通信

1 props传值

react组件通信_第1张图片

1.1 思路

渲染列表:App--->LIst  (数据放哪?自己--state;某些--父组件state--->app组件定义共享数组)

添加:header--->App:this.props.add()   onKeyUp

移入:加一个移入状态的标识控制是否显示  onMouseEnter/onMouseLeave

勾选:Item--->App:this.props.updateItem()

删除:Item--->App:this.props.delItem()

全选:Footer--->App:onChange(全选/取消)+checked(勾选数=总数)

1.2 编码

父组件向子组件传值;

子组件调用父组件方法。

父组件

  // 方法
  addTodo = (todoObj) => {
    const { todos } = this.state
    const newTodos = [todoObj, ...todos]
    this.setState({
      todos: newTodos
    })
  }
  //数据
  state = {
    todos: [
      { id: '001', name: '吃饭', done: true },
      { id: '002', name: '睡觉', done: true },
      { id: '003', name: '打代码', done: false },
      { id: '004', name: '逛街', done: false }
    ]
  }
  render () {
    const { todos } = this.state
    return (
      
) }

 子组件

  import { PropTypes } from 'prop-types'  
  //接收父组件函数  
  static propsTypes = {
    addTodo: PropTypes.func.isRequied
  }
  //子组件调用父组件方法
  addTodo = (event) => {
    //...
    this.props.addTodo(todoItem)
  }
  render () {
    //接收父组件数据
    const { todos} = this.props
    return (
      
) }

1.3 renderProps

如何向组件内部动态传入带内容的结构?

     Vue中:

        使用slot技术, 也就是通过组件标签体传入结构  

    React中:

        使用children props: 通过组件标签体传入结构

        使用render props: 通过组件标签属性传入结构, 一般用render函数属性

import React, { Component } from 'react'
import './index.css'
import C from '../1_setState'

export default class Parent extends Component {
	render() {
		return (
			

我是Parent组件

{/*返回B组件或者任意组件*/} }/>
) } } class A extends Component { state = {name:'tom'} render() { console.log(this.props); const {name} = this.state return (

我是A组件

{/*占位:相当于插槽,可传值*/} {this.props.render(name)}
) } } class B extends Component { render() { console.log('B--render'); return (
{/*读取A组件传入的数据显示*/}

我是B组件,{this.props.name}

) } }
xxxx {this.props.children} 问题: 如果B组件需要A组件内的数据, ==> 做不到

 

2 PubSub

适用于任意组件通信

import PubSub from 'pubsub-js'
//发布
PubSub.publish('updateList', data)

//订阅
componentDidMount () {
    this.token = PubSub.subscribe('updateList', (_, data) => {
      console.log(data, '接受的数据');
      console.log(_, '第一个参数');
    })
}
//取消订阅
componentWillUnmount () {
    PubSub.unsubscribe(this.token);
}

3 redux

3.1 简介

redux:状态管理(共享状态、组件通信 )

react组件通信_第2张图片

3.2 编码

3.2.1 Count.jsx(组件)

import store from './redux/store'
import { createDecrementAction } from './redux/action'

//取值
const count = store.getState();
if (count % 2 === 1) {
   //分发
   store.dispatch(createIncrementAction(value * 1))
}

componentDidMount () {
    //检测redux中状态的变化,只要变化,就调用render
    store.subscribe(() => {
      this.setState({})
    })
}

3.2.2 redux/constant.js

export const INCREMENT = 'increment'
export const DECREMENT = 'decrement'

3.2.3 redux/action.js

import { INCREMENT, DECREMENT } from './constant'
//同步action,值为一般对象
export const createIncrementAction = data => ({ type: INCREMENT, data })
export const createDecrementAction = data => ({ type: DECREMENT, data })
//异步action,值为函数。异步任务有结果后,分发一个同步action操作数据。不是必须要用的,可放在组件中。
export const createIncrementAsyncAction = (data, time) => {
  return (dispatch) => {
    setTimeout(() => {
      dispatch(createIncrementAction(data))
    },time)
  }
}

3.2.4 redux/reducer.js

import {INCREMENT,DECREMENT} from './constant'
const initState = 0
export default function countReducer (preState = initState, action) {//reducer函数会接到两个参数:之前的状态(preState),动作对象(action)
  console.log(preState,action,'初始化');//0 {type: '@@redux/INIT2.0.y.s.0.h'}
  const { type, data } = action
  switch (type) {
    case INCREMENT:
      return preState + data
    case DECREMENT:
      return preState - data
    default:
      return preState
  }
}

3.2.5 redux/store.js

import { createStore,applyMiddleware,combineReducers } from 'redux'
import countReducer from './reducer'
// 用于支持异步action
import thunk from 'redux-thunk'
//引入redux-devtools-extension
import {composeWithDevTools} from 'redux-devtools-extension'

//汇总reducer:实现数据共享
const allReducer = combineReducers({
  he: countReducer,
  rens:personReducer
})

// 暴露一个store对象
export default createStore(allReducer ,composeWithDevTools(applyMiddleware(thunk)))

react-redux

4.1 原理

react组件通信_第3张图片

4.2 编码

4.2.1 index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import store from './redux/store'
import {Provider} from 'react-redux'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  
    {/* 统一传一次store,无需在APP中多次传递store,让App所有的后代容器组件都能接收到store */}
    
      
    
  
);

4.2.2 Count.jsx(容器组件)

import { createIncrementAction } from './redux/action'
import { connect } from 'react-redux'

class Count extends Component {
  incrementIfOdd = () => {
    const { value } = this.selectNum
    if (this.props.count % 2 === 1) {//取值
      this.props.jia(value * 1)//分发
    }
  }
}

//写法一
const mapStateToProps = (state) => {//用于传递状态
  return { count: state.he }//传递给UI组件props
}

const mapDispatchToProps = (dispatch) => {//用于传递操作状态的方法
  return {//传递给UI组件props
    jia: number => dispatch(createIncrementAction(number)),
    jian: number => dispatch(createDecrementAction(number)),
    jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number, time)),
  }
}
//暴露一个Count的容器组件
export default connect(mapStateToProps, mapDispatchToProps)(Count)

// 写法二:简写
export default connect(
  state => ({ count: state }),
  // 函数写法1:语法简写
  // dispatch => ({
  //   jia: number => dispatch(createIncrementAction(number)),
  //   jian: number => dispatch(createDecrementAction(number)),
  //   jiaAsync: (number, time) => dispatch(createIncrementAsyncAction(number, time)),
  // })
  // 对象写法2:dispatch由react分发
  {
    jia: createIncrementAction,
    jian: createDecrementAction,
    jiaAsync: createIncrementAsyncAction,
  }
)(Count)

redux/constant.js

同上

redux/action.js

同上

redux/reducer.js

同上

纯函数:同样输入,必须得到同样输出。redux的reducer必须是一个纯函数。

react组件通信_第4张图片  

import {ADD_PERSON} from '../constant'

//初始化人的列表
const initState = [{id:'001',name:'tom',age:18}]

export default function personReducer(preState=initState,action){
	// console.log('personReducer@#@#@#');
	const {type,data} = action
	switch (type) {
		case ADD_PERSON: //若是添加一个人
            //unshift添加数据后无法更新页面,数组地址不变,所以未更新。此时reducer不是纯函数。
			//preState.unshift(data) //此处不可以这样写,这样会导致preState被改写了,personReducer就不是纯函数了。
			return [data,...preState]
		default:
			return preState
	}
}

redux/store.js

同上

Context

祖孙组件通信,在应用开发中一般不用context, 一般都它的封装react插件。
import React, { Component } from 'react'
import './index.css'

//创建Context对象
const MyContext = React.createContext()
const {Provider,Consumer} = MyContext

//A>B>C
export default class A extends Component {

	state = {username:'tom',age:18}

	render() {
		const {username,age} = this.state
		return (
			

我是A组件

我的用户名是:{username}

) } } class B extends Component { render() { return (

我是B组件

) } } //类组件 /* class C extends Component { //声明接收context static contextType = MyContext render() { const {username,age} = this.context return (

我是C组件

我从A组件接收到的用户名:{username},年龄是{age}

) } } */ //函数组件 function C(){ return (

我是C组件

我从A组件接收到的用户名: {value => `${value.username},年龄是${value.age}`}

) }

你可能感兴趣的:(react,react.js)