React基础梳理,万字总结,总能帮到你~
第1章:React入门
1.1.React简介
- 1.英文官网: reactjs.org/
- 2.中文官网: react.docschina.org/
- 3.用于动态构建用户界面的 JavaScript 库(只关注于视图)
- 4.Facebook开源
React的特点
- 1.声明式编码
- 2.组件化编码
- 3.React Native 编写原生应用
- 4.高效(优秀的Diffing算法)
React高效的原因
- 1.使用虚拟(virtual)DOM, 不总是直接操作页面真实DOM。
- 2.DOM Diffing算法, 最小化页面重绘。
1.2.React的基本使用
相关js库
- 1.react.js:React核心库。
- 2.react-dom.js:提供操作DOM的react扩展库。
- 3.babel.min.js:解析JSX语法代码转为JS代码的库。
创建虚拟DOM的两种方式
- 1.纯JS方式(一般不用)
- 2.JSX方式
虚拟DOM与真实DOM
- 1.通过一些API来创建一种 “特别” 的一般js对象,例如:
const VDOM = React.createElement('xx',{id:'xx'},'xx')
,这就是一个简单的虚拟DOM对象 - 2.虚拟DOM对象最终都会被React转换为真实的DOM。我们编码时基本只需要操作react的虚拟DOM相关数据, react会转换为真实DOM变化而更新界面。
1.3.React JSX
JSX
- 1.全称: JavaScript XML
- 2.react定义的一种类似于XML的JS扩展语法: React.createElement(component, props, ...children)方法的语法糖
- 3.作用: 用来简化创建虚拟DOM
- 4.标签名任意: HTML标签或其它标签
- 5.标签属性任意: HTML标签属性或其它
- 6.基本语法规则:
- 遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析
- 遇到以 { 开头的代码,以JS语法解析: 标签中的js表达式必须用{ }包含
- 7.babel.js的作用
- 浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行
- 只要用了JSX,都要加上type="text/babel", 声明需要babel来处理
渲染虚拟DOM(元素)
- 1.语法: ReactDOM.render(virtualDOM, containerDOM)
- 2.作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
- 3.参数说明:
- 参数一: 纯js或jsx创建的虚拟dom对象
- 参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)
1.2.模块与组件、模块化与组件化的理解
模块和模块化
- 1.理解:向外提供特定功能的js程序, 一般就是一个js文件
- 2.为什么要拆成模块?随着业务逻辑增加,代码越来越多且复杂。
- 3.作用 —— 复用js, 简化js的编写, 提高js运行效率
- 4.当应用的js都以模块来编写的, 这个应用就是一个模块化的应用
组件和组件化
- 1.理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
- 2.为什么要用组件? 一个界面的功能更复杂
- 3.作用 —— 复用编码, 简化项目编码, 提高运行效率
- 4.当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
第2章:React面向组件编程
2.1 组件三大核心属性之 —— state
- 1.state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
- 2.组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
强烈注意
- 1.组件中render方法中的this为组件实例对象
- 2.组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的bind()
- 箭头函数
- 3.状态数据,不能直接修改或更新
2.2 组件三大核心属性之 —— props
- 1.每个组件对象都会有props(properties的简写)属性
- 2.组件标签的所有属性都保存在props中
- 3.通过标签属性从组件外向组件内传递变化的数据
- 4.注意 —— 组件内部无法修改props数据
对props中的属性值进行类型限制和必要性限制
// 第一种方式(React v15.5 开始已弃用)
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number
}
// 第二种方式 —— 使用prop-types库进限制(需要引入prop-types库)
class Person extends React.Component{
render(){
const {name,age,sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('root'))
2.3 组件三大核心属性之 —— refs与事件处理
ref —— 组件内的标签可以定义ref属性来标识自己:
- 1.字符串形式的ref:
<input ref="input1"/>
- 2.回调形式的ref:
<input ref={(val)=>{this.input1 = val}}/>
- 3.createRef创建ref容器:
myRef = React.createRef()
<input ref={this.myRef}/>
事件处理
- 1.通过onXxx属性(例如:onClick)指定事件处理函数(注意大小写)
-
- React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
-
- React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
-
- 2.通过event.target得到发生事件的DOM元素对象
受控组件和非受控组件
React 中的受控组件和非受控组件都是针对于表单数据而言的。React 推荐使用受控组件来处理表单数据。 在受控组件中,表单数据由React组件的state管理。在非受控组件中,表单数据交由DOM节点处理,可以使用ref来从 DOM中获取表单数据。
// 受控组件 —— React 的 state 是表单的数据源,并且渲染表单的 React 组件还控制着用户输入过程中表单发生的操作
function Form() {
const [name, setName] = useState('');
const onInputChange = event => setName(event.target.value);
const onFormSubmit = event => {
console.log('提交的数据 => ', name);
event.preventDefault();
};
return (
<form onSubmit={onFormSubmit}>
<label>
名字:
<input type='text' value={name} onChange={onInputChange} />
</label>
<input type='submit' value='提交'/>
</form>
)
}
// 非受控组件 —— 表单元素自己维护 state。可以使用 ref 获取表单数据
function Form() {
const inputElement = useRef(null);
const onFormSubmit = event => {
console.log('提交的数据 => ', inputElement.current.value);
event.preventDefault();
};
return (
<form onSubmit={onFormSubmit}>
<label>
名字:
<input type='text' ref={inputElement} />
</label>
<input type='submit' value='提交'/>
</form>
)
}
2.4 组件的生命周期
理解 React 的生命周期
- 组件从创建到死亡它会经历一些特定的阶段。
- React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
- 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
生命周期流程图(旧)
-
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
- 1.constructor()
- 2.componentWillMount()
- 3.render()
- 4.componentDidMount()
-
- 更新阶段: 由组件内部this.setSate()或父组件重新render触发
- 1.shouldComponentUpdate()
- 2.componentWillUpdate()
- 3.render()
- 4.componentDidUpdate()
-
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- 1.componentWillUnmount()
生命周期流程图(新)
-
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
- 1.constructor()
- 2.getDerivedStateFromProps
- 3.render()
- 4.componentDidMount()
-
- 更新阶段: 由组件内部this.setSate()或父组件重新render触发
- 1.getDerivedStateFromProps
- 2.shouldComponentUpdate()
- 3.render()
- 4.getSnapshotBeforeUpdate
- 5.componentDidUpdate()
-
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- 1.componentWillUnmount()
2.5 虚拟DOM与DOM Diffing算法
第3章:基于脚手架的react应用
3.1 使用create-react-app创建react应用
- 第一步,全局安装:npm i -g create-react-app
- 第二步,切换到想创项目的目录,使用命令:create-react-app hello-react
- 第三步,进入项目文件夹:cd hello-react
- 第四步,启动项目:npm start
// react脚手架项目结构
public ---- 静态资源文件夹
favicon.icon ------ 网站页签图标
index.html -------- 主页面
logo192.png ------- logo图
logo512.png ------- logo图
manifest.json ----- 应用加壳的配置文件
robots.txt -------- 爬虫协议文件
src ---- 源码文件夹
App.css -------- App组件的样式
App.js --------- App组件
App.test.js ---- 用于给App做测试
index.css ------ 样式
index.js ------- 入口文件
logo.svg ------- logo图
reportWebVitals.js
--- 页面性能分析文件(需要web-vitals库的支持)
setupTests.js
---- 组件单元测试的文件(需要jest-dom库的支持)
3.2 功能界面的组件化编码流程(通用)
-
- 拆分组件: 拆分界面,抽取组件
-
- 实现静态组件: 使用组件实现静态页面效果
-
- 实现动态组件
- 3.1 动态显示初始化数据
- 3.1.1 数据类型
- 3.1.2 数据名称
- 3.1.2 保存在哪个组件?
- 3.2 交互(从绑定事件监听开始)
3.3 react脚手架配置代理
- 第一步:创建代理配置文件
在src下创建配置文件:src/setupProxy.js
- 编写setupProxy.js配置具体代理规则:
const proxy = require('http-proxy-middleware')
module.exports = function(app) {
app.use(
proxy('/api1', { //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
changeOrigin: true, //控制服务器接收到的请求头中host字段的值
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin默认值为false,但我们一般将changeOrigin值设为true
*/
pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
}),
proxy('/api2', {
target: 'http://localhost:5001',
changeOrigin: true,
pathRewrite: {'^/api2': ''}
})
)
}
4. React路由
4.1 SPA的理解
- 1.单页Web应用(single page web application,SPA)。
- 2.整个应用只有一个完整的页面。
- 3.点击页面中的链接不会刷新页面,只会做页面的局部更新。
- 4.数据都需要通过ajax请求获取, 并在前端异步展现。
4.2 路由的理解
-
- 什么是路由?
- 一个路由就是一个映射关系(key:value)
- key为路径, value可能是function或component
- 路由分类
-
- 后端路由:
- 理解: value是function, 用来处理客户端提交的请求。
- 注册路由: router.get(path, function(req, res))
- 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
-
- 前端路由:
- 浏览器端路由,value是component,用于展示页面内容。
- 注册路由:
<Route path="/test" component={Test}>
- 工作过程:当浏览器的path变为/test时, 当前路由组件就会变为Test组件
4.3 React 路由使用
react-router-dom
是一个处理页面跳转的三方库,在使用之前需要先安装到我们的项目中:
# npm
npm install react-router-dom
# yarn
yarn add react-router-dom
混合组件化
index
=>home
=>main/about/topics
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Home from './pages/route-demo/home';
ReactDOM.render(<Home />, document.getElementById('root'));
// route-demo/home
import React, { Component } from 'react';
import { HashRouter, Route, Link, Switch } from 'react-router-dom';
import Main from './main'
import About from './about'
import Topics from './topics'
class Home extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<HashRouter>
{/* HashRouter里面一定要有一个根节点,不能直接写Route */}
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">about</Link></li>
<li><Link to="/topics">topics</Link></li>
</ul>
<hr />
{/* exact 精准匹配 */}
<Route exact path="/" component={Main}></Route>
<Route path="/about" component={About}></Route>
<Route path="/topics" component={Topics}></Route>
</div>
</HashRouter>
);
}
}
export default Home;
路由配置化
- 路由配置化:把路由单独抽取出来,不和link写在一起
this.props.children
表示组件所有的子节点。index
=>router
=>home
=>admin/about/contact
// router.js
class IRouter extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<BrowserRouter>
<Home>
<Route exact path='/' component={Admin} />
<Route path='/about' component={About} />
<Route path='/contact' component={Contact} />
</Home>
</BrowserRouter>
);
}
}
export default IRouter;
// home.js
class Home extends Component {
render() {
return (
<div>
<ul>
<li><Link to='/'>Home</Link></li>
<li><Link to='/about'>About Us</Link></li>
<li><Link to='/contact'>Contact Us</Link></li>
</ul>
<hr />
{this.props.children}
</div>
)
}
}
export default Home;
嵌套路由
- 一级路由
index
=>router
=>home
=>admin/about/contact
- 二级路由
admin
=>公司/文化/员工
// home.js
class Home extends Component {
render() {
return (
<div>
<ul>
<li><Link to='/admin'>Home</Link></li>
<li><Link to='/about'>About Us</Link></li>
<li><Link to='/contact'>Contact Us</Link></li>
</ul>
<hr />
{this.props.children}
</div>
)
}
}
export default Home;
//router.js
class IRouter extends Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<BrowserRouter>
<Home>
{/* 嵌套路由不用写component 写render 继续渲染下一级路由 */}
{/* 嵌套路由 不能加exact 否则不能匹配到`/admin` 只能精准匹配到`/` */}
<Route path='/admin' render={()=>
<Admin>
<Route path='/admin/company' component={About} />
<Route path='/admin/culture' component={About} />
<Route path='/admin/people' component={About} />
</Admin>
} />
<Route path='/about' component={About} />
<Route path='/contact' component={Contact} />
</Home>
</BrowserRouter>
);
}
}
export default IRouter;
// admin.js
class Admin extends Component {
render() {
return (
<div>
This is Admin Page.
<ul>
<li><Link to='/admin/company'>公司</Link></li>
<li><Link to='/admin/culture'>文化</Link></li>
<li><Link to='/admin/people'>员工</Link></li>
</ul>
<hr />
{this.props.children}
</div>
);
}
}
export default Admin;
5. redux
redux是什么
- redux是一个专门用于做状态管理的JS库(不是react插件库)。
- 它可以用在react, angular, vue等项目中, 但基本与react配合使用。
- 作用 —— 集中式管理react应用中多个组件共享的状态。
什么情况下需要使用redux
- 某个组件的状态,需要让其他组件可以随时拿到(共享)。
- 一个组件需要改变另一个组件的状态(通信)。
- 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。
5.1 redux的三个核心概念
action
- 动作的对象
- 包含2个属性
- type:标识属性, 值为字符串, 唯一, 必要属性
- data:数据属性, 值类型任意, 可选属性
- 例子:
{ type: 'ADD_STUDENT', data : {name: 'tom',age:18} }
reducer
- 用于初始化状态、加工状态。
- 加工时,根据旧的state和action, 产生新的state的纯函数。
store
- 将state、action、reducer联系在一起的对象
- 如何得到此对象?
- 1.import {createStore} from 'redux'
- 2.import reducer from './reducers'
- 3.const store = createStore(reducer)
- 此对象的功能?
- 1.getState(): 得到state
- 2.dispatch(action): 分发action, 触发reducer调用, 产生新的state
- 3.subscribe(listener): 注册监听, 当产生了新的state时, 自动调用
5.2 redux的核心API
createstore()
作用:创建包含指定reducer的store对象
store对象
-
- 作用: redux库最核心的管理对象
-
- 它内部维护着:
- 1)state
- 2)reducer
-
- 核心方法:
- 1)getState()
- 2)dispatch(action)
- 3)subscribe(listener)
-
- 具体编码:
- 1)store.getState()
- 2)store.dispatch({type:'INCREMENT', number})
- 3)store.subscribe(render)
applyMiddleware()
作用:应用上基于redux的中间件(插件库)
combineReducers()
作用:合并多个reducer函数
5.3 redux 用法示例
- 在src 目录下新建redux 文件目录,新建核心文件 store.js
import { createStore , combineReducers} from 'redux';
import countReducer from './count_reducer';
import colorReducer from './color_reducer';
// 使用该方法合并两个reducer
const rootReducer = combineReducers({
countReducer,
colorReducer
});
const store = createStore(rootReducer);
export default store;
- 实现一个简单的加、减法的求和计算器:
import React, { Component } from 'react'
import store from '../redux/store';
export class Count extends Component {
constructor(props) {
super(props);
this.state = {count: 0};
}
componentDidMount() {
store.subscribe(() => {
this.setState({});
})
}
increment = ()=> {
const {value} = this.selectNumber;
store.dispatch({type: 'increment', data: Number(value)});
}
decrement = ()=> {
const {value} = this.selectNumber;
store.dispatch({type: 'decrement', data: Number(value)});
}
incrementIfOdd = ()=> {
const {value} = this.selectNumber;
const count = store.getState().countReducer;
if(count % 2 !== 0) {
store.dispatch({type: 'increment', data: Number(value)});
}
}
incrementAsync = ()=> {
setTimeout(() => {
const {value} = this.selectNumber;
store.dispatch({type: 'increment', data: Number(value)});
}, 500)
}
render() {
return (
<div>
<h1>当前求和为: {store.getState().countReducer}</h1>
<select ref={val => this.selectNumber = val} style={{width: '50px'}}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步求和</button>
</div>
)
}
}
export default Count
- 在redux 目录下新建 count 的reducer —— count_reducer.js
/**
* 创建一个为组件count 服务的reducer
*/
const initState = 0;
export default function countReducer(prestate = initState, action) {
const {type, data} = action;
console.log(action);
switch(type) {
case 'increment': return prestate + data;
case 'decrement': return prestate - data;
default: return initState;
}
}
第6章:react的扩展核心知识
6.1. setState
setState更新状态的2种写法
(1). setState(stateChange, [callback])------对象式的setState
1.stateChange为状态改变对象(该对象可以体现出状态的更改)
2.callback是可选的回调函数, 它在状态更新完毕、界面也更新后(render调用后)才被调用
(2). setState(updater, [callback])------函数式的setState
1.updater为返回stateChange对象的函数。
2.updater可以接收到state和props。
4.callback是可选的回调函数, 它在状态更新、界面也更新后(render调用后)才被调用。
总结:
- 1.对象式的setState是函数式的setState的简写方式 (语法糖)
- 2.使用原则:
- (1).如果新状态不依赖于原状态 ===> 使用对象方式
- (2).如果新状态依赖于原状态 ===> 使用函数方式
- (3).如果需要在setState()执行后获取最新的状态数据, 要在第二个callback函数中读取
6.2. lazyLoad
路由组件的lazyLoad
// 1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
const Login = lazy(()=>import('@/pages/Login'))
// 2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
<Suspense fallback={<h1>loading.....</h1>}>
<Switch>
<Route path="/xxx" component={Xxxx}/>
<Redirect to="/login"/>
</Switch>
</Suspense>
6.3. Hooks
6.3.1. React Hook/Hooks是什么?
(1). Hook是React 16.8.0版本增加的新特性/新语法
(2). 可以让你在函数组件中使用 state 以及其他的 React 特性
6.3.2. State Hook
(1). State Hook让函数组件也可以有state状态, 并进行状态数据的读写操作
(2). 语法: const [xxx, setXxx] = React.useState(initValue)
(3). useState() 说明:
参数: 第一次初始化指定的值在内部作缓存
返回值: 包含2个元素的数组, 第1个为内部当前状态值, 第2个为更新状态值的函数
(4). setXxx() 2种写法:
setXxx(newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
setXxx(value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态值
6.3.3. Effect Hook
(1). Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类组件中的生命周期钩子)
(2). React中的副作用操作:
发ajax请求数据获取
设置订阅 / 启动定时器
手动更改真实DOM
(3). 语法和说明:
useEffect(() => {
// 在此可以执行任何带副作用操作
return () => { // 在组件卸载前执行
// 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [stateValue]) // 如果指定的是[], 回调函数只会在第一次render()后执行
(4). 可以把 useEffect Hook 看做如下三个函数的组合
componentDidMount()
componentDidUpdate()
componentWillUnmount()
6.3.4. Ref Hook
(1). Ref Hook可以在函数组件中存储/查找组件内的标签或任意其它数据
(2). 语法: const refContainer = useRef()
(3). 作用:保存标签对象,功能与React.createRef()一样
6.4. Context
理解
一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信,常用于解决跨多层父子组件间的数据交互问题。
使用
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>
注意
在应用开发中一般不用context, 一般都用它的封装react插件
Context 的使用作用可以对比 vue的 provider/inject:
// 父组件 provide 中提供变量,子组件 inject 中来注入,然后可以在子组件内部使用 provide 的变量
// Father.vue
provide(){
return {
demo: this.demoFn,
}
}
......
methods:{
demoFn(){
this.flag = false
this.$nextTick(function(){
this.flag = true
})
}
}
// child.vue
...
inject: ['demo']
...
通过inject引入后直接调用 `this.demo()` 即可
6.5. 组件优化
Component的2个问题
-
- 只要执行setState(),即使不改变状态数据, 组件也会重新render() ==>
效率低
- 只要执行setState(),即使不改变状态数据, 组件也会重新render() ==>
-
- 只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==>
效率低
- 只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据 ==>
效率高的做法
只有当组件的state或props数据发生改变时才重新render()
原因
Component中的shouldComponentUpdate()总是返回true
解决
- 办法1: 重写shouldComponentUpdate()方法 比较新旧state或props数据, 如果有变化才返回true, 如果没有返回false
- 办法2: 使用PureComponent PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true 注意: 只是进行state和props数据的浅比较, 如果只是数据对象内部数据变了, 返回false 不要直接修改state数据, 而是要产生新数据 项目中一般使用PureComponent来优化
6.6. render props
如何向组件内部动态传入带内容的结构(标签)?
- Vue中:
- 使用slot技术, 也就是通过组件标签体传入结构
- React中:
- 使用children props: 通过组件标签体传入结构
- 使用render props: 通过组件标签属性传入结构,而且可以携带数据,一般用render函数属性
children props
<A>
<B>xxxx</B>
</A>
{this.props.children}
问题: 如果B组件需要A组件内的数据, ==> 做不到
render props
<A render={(data) =>
<C data={data}></C>}>
</A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data}
6.7. 组件通信方式总结
组件间的关系:
- 父子组件
- 兄弟组件(非嵌套组件)
- 祖孙组件(跨级组件)
几种通信方式:
1.props:
(1).children props
(2).render props
2.消息订阅-发布:
pubs-sub、event等等
3.集中式管理:
redux、dva等等
4.conText:
生产者-消费者模式
比较好的搭配方式:
父子组件:props
兄弟组件:消息订阅-发布、集中式管理
祖孙组件(跨级组件):消息订阅-发布、集中式管理、conText(开发用的少,封装插件用的多)
转载自:https://juejin.cn/post/7170271990253617183