render()函数的返回值
当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:
React 元素:
- 口 通常通过JSX 创建。
- 口 例如,
会被 React 渲染为 DOM 节点,
会被 React 渲染为自定义组件;
- 口 无论是
还是
均为 React 元素。
数组或 fragments:使得 render 方法可以返回多个元素。
Portals: 可以渲染子节点到不同的 DOM 子树中。
-字符串或数值类型:它们在 DOM 中会被渲染为文本节点
布尔类型或 null:什么都不渲染。
export default function App(){
return HelLo World
}
很多的事物都有从创建到销毁的整个过程,这个过程称之为是生命周期:
React组件也有自己的生命周期,了解组件的生命周期可以让我们在最合适的地方完成自己想要的功能:
生命周期和生命周期函数的关系:
生命周期 是一个 抽象的概念,在生命周期的整个过程,分成了很多个阶段;
React内部为了告诉我们当前处于哪些阶段,会对我们组件内部实现的某些函数进行回调,这些函数就是生命周期函数:
我们谈到React生命周期时,主要谈的是类的生命周期,因为函数式组件没有生命周期。(后面可以通过hooks模拟生命周期的回调)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qu6AHfUh-1687143660083)(file:///Volumes/web/0%E9%9D%A2%E8%AF%952023/%E9%A1%B9%E7%9B%AE%E6%88%AA%E5%9B%BE/%E6%88%AA%E5%B1%8F2023-06-15%2012.00.28.png)]
对于传递给子组件的数据,有时候我们可能希望进行验证,特别是对于大型项目来说:
更多的验证方式,可以参考官网:https//zh-hans.reactis.org/docs/typeche,king-with-proptypes.htm
如果没有传递,我们希望有默认值
ChildCpn.propTypes = {
name:PropTypes.string,
age:PropTypes.number,
height:PropTypes.number
}
某些情况,我们也需要子组件向父组件传递消息:
我们这里来完成一个案例:
// 父组件
import React, { Component } from 'react';
import CounterButton from './CounterButton';
import SubCounter from './SubCounter';
class App extends Component {
constructor() {
super();
this.state = {
counter: 0,
};
}
counterClick(count) {
this.setState({
counter: this.state.counter + count,
});
}
render() {
const { counter } = this.state;
return (
05_组件通信-子传父
当前计数:{counter}
this.counterClick(count)}>
this.counterClick(count)}>
);
}
}
export default App;
// 子组件
import React, { Component } from 'react';
class CounterButton extends Component {
addCount(count) {
this.props.addClick(count);
}
render() {
return (
);
}
}
export default CounterButton;
// 子组件
import React, { Component } from 'react';
class SubCounter extends Component {
subCount(count) {
this.props.subClick(count);
}
render() {
return (
);
}
}
export default SubCounter;
在开发中,我们抽取了一个组件,但是为了让这个组件具备更强的通用性,我们不能将组件中的内容限制为固定的div、span等等这些元素。
我们应该让使用者可以决定某一块区域到底存放什么内容。
这种需求在Vue当中有一个固定的做法是通过slot来完成的,React呢?
React对于这种需要插槽的情况非常灵活,有两种方案可以实现:
每个组件都可以获取到 props.children:它包含组件的开始标签和结束标签之间的内容。
只传入一个元素时,children就是当前元素
传入多个元素时,children为数组
class App extends Component {
render() {
return (
07_组件的插槽
标题
);
}
}
class index extends Component {
render() {
const { children } = this.props;
return (
{children[0]}
{children[1]}
{children[2]}
);
}
}
返回2}
centerSlot={标题2
}
rightSlot={}
>
class index extends Component {
render() {
const { leftSlot, centerSlot, rightSlot } = this.props;
return (
{leftSlot}
{centerSlot}
{rightSlot}
);
}
}
非父子组件数据的共享:
口 在开发中,比较常见的数据传递方式是通过props属性自上而下(由父到子)进行传递。
口 但是对于有一些场景: 比如一些数据需要在多个组件中进行共享(地区偏好、UI主题、用户登录状态、用户信息等)。
口 如果我们在顶层的App中定义这些信息,之后一层层传递下去,那么对于一些中间层不需要数据的组件来说,是一种冗余的操作。
我们实现一个一层层传递的案例:
但是,如果层级更多的话,一层层传递是非常麻烦,并且代码是非常冗余的:
React.createContext
const myContext = React.createContext(defaultValue)
Context.Provider
Class.contextType
myClass.contextType = myContext;
Context.Consumer
什么时候使用Context.Consumer呢?
npm install hy-event-bus
开发中我们井不能直接通过修改state的值来让界面发生更新:
?疑惑:在组件中井没有实现setState的方法,为什么可以调用呢?
Component.prototype.setState = function (partialState, callback) {
if (
typeof partialState !== 'object' &&
typeof partialState !== 'function' &&
partialState != null
) {
throw new Error(
'setState(...): takes an object of state variables to update or a ' +
'function which returns an object of state variables.',
);
}
this.updater.enqueueSetState(this, partialState, callback, 'setState');
};
Object.assign(state,setState)
属性名相同的值会覆盖掉changeText() {
this.setState({
msg: 'new world!!!',
});
}
2.setState可以传入一个回调函数
this.setState((state, props) => {
// 1. 编写一些对新的state处理逻辑
// 2. 可以获取之前的 state和props值
console.log(state);
return {
msg: 'setState传入一个回调函数',
};
});
this.setState({ msg: 'new world!!!' }, () => {
console.log('++++++++', this.state.msg);
});
console.log('---------', this.state.msg);
setState的更新是异步的?
changeText() {
this.setState({ msg: 'new world!!!' }, () => {
console.log('++++++++', this.state.msg); //new world!!!
});
console.log('---------', this.state.msg); // hello world
}
为什么 setState 设计成为异步呢?
如何获取异步更新的结果?
方式一: setState 的回调
setState(partialState,callback)
方式二:在生命周期函数
componentDidUpdate(prevProps, provState, snapshot) {
console.log(this.state.msg);
}
React在props或state发送改变时,会调用React的render方法,会创建一颗不同的树。
React如果要基于这两颗不同的树之间的差别来判断如何有效的更新UI
于是,React 对这个算法进行了优化,将其优化成了O(n),
如何优化?
我们之前的一个嵌套案例
在开发中,我们只要修改了App中的数据,所有组件都需要重新rednder,进行diff算法,性能必然很低:
如何来控制render方法是否被调用呢?
shouldComponentUpdate
方法即可; if (ctor.prototype && ctor.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}
const Profile = memo(function (props) {
console.log('profile render');
return (
Profile:{props.msg}
);
});
export default Profile;
在React开发中,通常情况下不需要、也不建议直接操作原生DOM,但是某些特殊的情况,确实需要获取到DOM进行某些操作:
ref的类型
React中,获取DOM
export class App extends PureComponent {
constructor() {
super();
this.state = {};
this.titleRef = createRef();
this.titleEl = null;
}
getNativeDom() {
// 1. 在React元素上绑定一个ref字符串
// console.log(this.refs.why);
// 2. 提前创建好 ref 对象,createRef(),将创建出来的对象绑定到元素上
// console.log(this.titleRef.current);
// 3.传入一个回调函数,在对应的元素被渲染之后,回调函数被执行,并且将元素传入
console.log(this.titleEl);
}
render() {
return (
14_ref获取DOM
hello world
titleRef
(this.titleEl = el)}>传入一个回调函数
);
}
}
类组件
this.hwRef = createRef();
......
getComponennt() {
console.log(this.hwRef.current);
this.hwRef.current.test();
}
函数式组件
ref转发
ref不能应用于函数式组件
在开发中,想要获取函数式组件中某个元素的DOM
const HelloWorldFunc = forwardRef(function (props, ref) {
return (
HelloWorldFunc
hhh
);
});
在HTML中,表单元素(如:、
、
)之类的表单元素通常自己维护state,并根据用户输入进行更新。
但,在React中,可变控件(mutable state)通常保存在组件的 __state属性__中,并且 只能通过使用 setState()来更新。
由于,在表单元素上设置了 value属性,因此,显示的值始终为 this.state.value
,这使得 React 的state成为唯一数据源。
由于, handleUsernameChange 在每次按键时都会执行并更新 react的state,因此显示的值将随着用户输入而更新。
React 推荐大多数情况下,使用 受控组件 来处理表单数据;
如果要使用非受控组件中的数据,那么需要使用 ref 来从DOM节点中获取表单数据。
const EnhancedComponent = higherOrderComponent(WrapperComponent)
function hoc(WrapperComponent) {
// 1. 定义一个类组件
class NewWrapperComponent extends PureComponent {
render() {
return ;
}
}
NewWrapperComponent.displayName = "coderwhy"
return NewWrapperComponent;
}
组件的名称问题:
高阶组件并不是React API 的一部分,它是基于React的组合特性而形成的设计模式;
高阶组件在一些React第三方库中非常常见:
我们会发现利用高阶组件可以针对某些React代码进行更加优滩的处理。
其实早期的React有提供组件之间的一种复用方式是mixin,目前已经不再建议使用:
当然,HOC也有自己的一些缺陷:
Hooks的出現,是开创性的,它解决了很多React之前的存在的向题
某些情况下,我们希望渲染的内容独立于父组件,甚至是独立于当前挂载到的DOM元素中(默认都是挂载到id为root的DOM 元素上的)
Portal 提供了一种将子节点渲染到存在于父组件以外的 DOM 节点的优秀的方案:
ReactDoM. createPortal (child, container)
通常来讲,当你从组件的 render 方法返回一个元素时,该元素将被挂载到 DOM 节点中离其最近的父节点: 然而,有时候将子元素插入到 DOM 节点中的不同位置也是有好处的;
-Modal
<>>
;npm npm install react-transition-group --save
yarn yarn add react-transition-group