「React进阶」 React全部api解读+基础实践大全(夯实基础2万字总结)(工具类)

简介: 一份不错的 React 学习指南

接下来我们一起来探究一下react工具类函数的用法。

utils.jpg

createElement

一提到createElement,就不由得和JSX联系一起。我们写的jsx,最终会被 babel,用createElement编译成react元素形式。我写一个组件,我们看一下会被编译成什么样子,

如果我们在render里面这么写:

render(){
   
   
    return <div className="box" >
        <div className="item"  >生命周期</div>
        <Text  mes="hello,world"  />
        <React.Fragment> Flagment </React.Fragment>
        {
   
    /*  */ }
        text文本
    </div>
}

会被编译成这样:

render() {
   
   
    return React.createElement("div", {
   
    className: "box" },
            React.createElement("div", {
   
    className: "item" }, "\u751F\u547D\u5468\u671F"),
            React.createElement(Text, {
   
    mes: "hello,world" }),
            React.createElement(React.Fragment, null, " Flagment "),
            "text\u6587\u672C");
    }

当然我们可以不用jsx模式,而是直接通过createElement进行开发。

createElement模型:

React.createElement(
  type,
  [props],
  [...children]
)

createElement参数:

第一个参数:如果是组件类型,会传入组件,如果是dom元素类型,传入div或者span之类的字符串。

第二个参数::第二个参数为一个对象,在dom类型中为属性,在组件类型中为props

其他参数:,依次为children,根据顺序排列。

createElement做了些什么?

经过createElement处理,最终会形成 $$typeof = Symbol(react.element)对象。对象上保存了该react.element的信息。

cloneElement

可能有的同学还傻傻的分不清楚cloneElementcreateElement区别和作用。

createElement把我们写的jsx,变成element对象; 而cloneElement的作用是以 element 元素为样板克隆并返回新的 React 元素。返回元素的 props 是将新的 props 与原始元素的 props 浅层合并后的结果。

那么cloneElement感觉在我们实际业务组件中,可能没什么用,但是在一些开源项目,或者是公共插槽组件中用处还是蛮大的,比如说,我们可以在组件中,劫持children element,然后通过cloneElement克隆element,混入props。经典的案例就是 react-router中的Swtich组件,通过这种方式,来匹配唯一的 Route并加以渲染。

我们设置一个场景,在组件中,去劫持children,然后给children赋能一些额外的props:

function FatherComponent({
   
    children }){
   
   
    const newChildren = React.cloneElement(children, {
   
    age: 18})
    return <div> {
   
    newChildren } </div>
}

function SonComponent(props){
   
   
    console.log(props)
    return <div>hello,world</div>
}

class Index extends React.Component{
   
       
    render(){
   
         
        return <div className="box" >
            <FatherComponent>
                <SonComponent name="alien"  />
            </FatherComponent>
        </div>   
    }
}

打印:

cloneElment.jpg

完美达到了效果!

createContext

createContext用于创建一个Context对象,createContext对象中,包括用于传递 Context 对象值 valueProvider,和接受value变化订阅的Consumer

const MyContext = React.createContext(defaultValue)

createContext接受一个参数defaultValue,如果Consumer上一级一直没有Provider,则会应用defaultValue作为value只有当组件所处的树中没有匹配到 Provider 时,其 defaultValue 参数才会生效。

我们来模拟一个 Context.ProviderContext.Consumer的例子:

function ComponentB(){
   
   
    /* 用 Consumer 订阅, 来自 Provider 中 value 的改变  */
    return <MyContext.Consumer>
        {
   
    (value) => <ComponentA  {
   
   ...value} /> }
    </MyContext.Consumer>
}

function ComponentA(props){
   
   
    const {
   
    name , mes } = props
    return <div> 
            <div> 姓名: {
   
    name }  </div>
            <div> 想对大家说: {
   
    mes }  </div>
         </div>
}

function index(){
   
   
    const [ value , ] = React.useState({
   
   
        name:'alien',
        mes:'let us learn React '
    })
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <MyContext.Provider value={
   
   value}  >
          <ComponentB />
    </MyContext.Provider>
    </div>
}

打印结果:

createContent.jpg

ProviderConsumer的良好的特性,可以做数据的Consumer一方面传递value,另一方面可以订阅value的改变。

Provider还有一个特性可以层层传递value,这种特性在react-redux中表现的淋漓尽致。

createFactory

React.createFactory(type)

返回用于生成指定类型 React 元素的函数。类型参数既可以是标签名字符串(像是 'div' 或 'span'),也可以是 React 组件 类型 ( class 组件或函数组件),或是 React fragment 类型。

使用:

 const Text = React.createFactory(()=><div>hello,world</div>) 
function Index(){
   
     
    return <div style={
   
   {
   
    marginTop:'50px'  }} >
        <Text/>
    </div>
}

效果

createFactory.jpg

报出警告,这个api将要被废弃,我们这里就不多讲了,如果想要达到同样的效果,请用React.createElement

createRef

createRef可以创建一个 ref 元素,附加在react元素上。

用法:

class Index extends React.Component{
   
   
    constructor(props){
   
   
        super(props)
        this.node = React.createRef()
    }
    componentDidMount(){
   
   
        console.log(this.node)
    }
    render(){
   
   
        return <div ref={
   
   this.node} > my name is alien </div>
    }
}

个人觉得createRef这个方法,很鸡肋,我们完全可以class类组件中这么写,来捕获ref

class Index extends React.Component{
   
   
    node = null
    componentDidMount(){
   
   
        console.log(this.node)
    }
    render(){
   
   
        return <div ref={
   
   (node)=> this.node } > my name is alien </div>
    }
}

或者在function组件中这么写:

function Index(){
   
   
    const node = React.useRef(null)
    useEffect(()=>{
   
   
        console.log(node.current)
    },[])
    return <div ref={
   
   node} >  my name is alien </div>
}

isValidElement

这个方法可以用来检测是否为react element元素,接受待验证对象,返回true或者false。这个api可能对于业务组件的开发,作用不大,因为对于组件内部状态,都是已知的,我们根本就不需要去验证,是否是react element 元素。
但是,对于一起公共组件或是开源库,isValidElement就很有作用了。

实践

我们做一个场景,验证容器组件的所有子组件,过滤到非react element类型。

没有用isValidElement验证之前:

const Text = () => <div>hello,world</div> 
class WarpComponent extends React.Component{
   
   
    constructor(props){
   
   
        super(props)
    }
    render(){
   
   
        return this.props.children
    }
}
function Index(){
   
   
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <WarpComponent>
            <Text/>
            <div> my name is alien </div>
            Let's learn react together!
        </WarpComponent>
    </div>
}

过滤之前的效果

isValidElement.jpg

我们用isValidElement进行react element验证:

class WarpComponent extends React.Component{
   
   
    constructor(props){
   
   
        super(props)
        this.newChidren = this.props.children.filter(item => React.isValidElement(item) )
    }
    render(){
   
   
        return this.newChidren
    }
}

过滤之后效果

isValidElement111.jpg

过滤掉了非react elementLet's learn react together!

Children.map

接下来的五个api都是和react.Chidren相关的,我们来分别介绍一下,我们先来看看官网的描述,React.Children 提供了用于处理 this.props.children 不透明数据结构的实用方法。

有的同学会问遍历 children用数组方法,mapforEach 不就可以了吗? 请我们注意一下不透明数据结构,什么叫做不透明结构?

我们先看一下透明的结构:

class Text extends React.Component{
   
   
    render(){
   
   
        return <div>hello,world</div>
    }
}
function WarpComponent(props){
   
   
    console.log(props.children)
    return props.children
}
function Index(){
   
   
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <WarpComponent>
            <Text/>
            <Text/>
            <Text/>
            <span>hello,world</span>
        </WarpComponent>
    </div>
}

打印

chidrenmap.jpg

但是我们把Index结构改变一下:

function Index(){
   
   
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <WarpComponent>
            {
   
    new Array(3).fill(0).map(()=><Text/>) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}

打印

chidrenmap2.jpg

这个数据结构,我们不能正常的遍历了,即使遍历也不能遍历,每一个子元素。此时就需要 react.Chidren 来帮忙了。

但是我们把WarpComponent组件用react.Chidren处理children:

function WarpComponent(props){
   
   
    const newChildren = React.Children.map(props.children,(item)=>item)
    console.log(newChildren)
    return newChildren
}

此时就能正常遍历了,达到了预期效果。

C71364B2-25E8-4F7D-A26D-50CA36AF4E33.jpg

注意
如果 children 是一个 Fragment 对象,它将被视为单一子节点的情况处理,而不会被遍历。

Children.forEach

Children.forEachChildren.map 用法类似,Children.map可以返回新的数组,Children.forEach仅停留在遍历阶段。

我们将上面的WarpComponent方法,用Children.forEach改一下。

function WarpComponent(props){
   
   
    React.Children.forEach(props.children,(item)=>console.log(item))
    return props.children
}

Children.count

children 中的组件总数量,等同于通过 mapforEach 调用回调函数的次数。对于更复杂的结果,Children.count可以返回同一级别子组件的数量。

我们还是把上述例子进行改造:

function WarpComponent(props){
   
   
    const childrenCount =  React.Children.count(props.children)
    console.log(childrenCount,'childrenCount')
    return props.children
}   
function Index(){
   
   
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <WarpComponent>
            {
   
    new Array(3).fill(0).map((item,index) => new Array(2).fill(1).map((item,index1)=><Text key={
   
   index+index1} />)) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}

效果:

chidrencunt.jpg

Children.toArray

Children.toArray返回,props.children扁平化后结果。

function WarpComponent(props){
   
   
    const newChidrenArray =  React.Children.toArray(props.children)
    console.log(newChidrenArray,'newChidrenArray')
    return newChidrenArray
}   
function Index(){
   
   
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <WarpComponent>
            {
   
    new Array(3).fill(0).map((item,index)=>new Array(2).fill(1).map((item,index1)=><Text key={
   
   index+index1} />)) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}

效果:

chuldeanarrgy.jpg

newChidrenArray ,就是扁平化的数组结构。React.Children.toArray() 在拉平展开子节点列表时,更改 key 值以保留嵌套数组的语义。也就是说, toArray 会为返回数组中的每个 key 添加前缀,以使得每个元素 key 的范围都限定在此函数入参数组的对象内。

Children.only

验证 children 是否只有一个子节点(一个 React 元素),如果有则返回它,否则此方法会抛出错误。

不唯一

function WarpComponent(props){
   
   
    console.log(React.Children.only(props.children))
    return props.children
}   
function Index(){
   
   
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <WarpComponent>
            {
   
    new Array(3).fill(0).map((item,index)=><Text key={
   
   index} />) }
            <span>hello,world</span>
        </WarpComponent>
    </div>
}

效果

falseonly.jpg

唯一

function WarpComponent(props){
   
   
    console.log(React.Children.only(props.children))
    return props.children
}   
function Index(){
   
   
    return <div style={
   
   {
   
    marginTop:'50px' }} >
        <WarpComponent>
           <Text/>
        </WarpComponent>
    </div>
}

效果

only.jpg

React.Children.only() 不接受 React.Children.map() 的返回值,因为它是一个数组而并不是 React 元素。

相关文章
|
3月前
|
前端开发 JavaScript
深入理解并实践React Hooks —— useEffect与useState
深入理解并实践React Hooks —— useEffect与useState
160 1
|
2月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
223 2
|
28天前
|
前端开发 JavaScript API
探究 React Hooks:如何利用全新 API 优化组件逻辑复用与状态管理
本文深入探讨React Hooks的使用方法,通过全新API优化组件逻辑复用和状态管理,提升开发效率和代码可维护性。
|
1月前
|
前端开发 JavaScript
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
手敲Webpack 5:React + TypeScript项目脚手架搭建实践
|
2月前
|
前端开发 JavaScript API
React 组件 API
10月更文挑战第9天
21 0
|
3月前
|
前端开发 JavaScript UED
深入React Hooks与性能优化实践
深入React Hooks与性能优化实践
54 0
|
4月前
|
开发者 安全 UED
JSF事件监听器:解锁动态界面的秘密武器,你真的知道如何驾驭它吗?
【8月更文挑战第31天】在构建动态用户界面时,事件监听器是实现组件间通信和响应用户操作的关键机制。JavaServer Faces (JSF) 提供了完整的事件模型,通过自定义事件监听器扩展组件行为。本文详细介绍如何在 JSF 应用中创建和使用事件监听器,提升应用的交互性和响应能力。
41 0
|
4月前
|
开发者 Java
JSF EL 表达式:乘技术潮流之风,筑简洁开发之梦,触动开发者心弦的强大语言
【8月更文挑战第31天】JavaServer Faces (JSF) 的表达式语言 (EL) 是一种强大的工具,允许开发者在 JSF 页面和后台 bean 间进行简洁高效的数据绑定。本文介绍了 JSF EL 的基本概念及使用技巧,包括访问 bean 属性和方法、数据绑定、内置对象使用、条件判断和循环等,并分享了最佳实践建议,帮助提升开发效率和代码质量。
56 0
|
4月前
|
开发者
告别繁琐代码,JSF标签库带你走进高效开发的新时代!
【8月更文挑战第31天】JSF(JavaServer Faces)标准标签库为页面开发提供了大量组件标签,如`&lt;h:inputText&gt;`、`&lt;h:dataTable&gt;`等,简化代码、提升效率并确保稳定性。本文通过示例展示如何使用这些标签实现常见功能,如创建登录表单和展示数据列表,帮助开发者更高效地进行Web应用开发。
47 0
|
4月前
|
前端开发 Java UED
瞬间变身高手!JSF 与 Ajax 强强联手,打造极致用户体验的富客户端应用,让你的应用焕然一新!
【8月更文挑战第31天】JavaServer Faces (JSF) 是 Java EE 标准的一部分,常用于构建企业级 Web 应用。传统 JSF 应用采用全页面刷新方式,可能影响用户体验。通过集成 Ajax 技术,可以显著提升应用的响应速度和交互性。本文详细介绍如何在 JSF 应用中使用 Ajax 构建富客户端应用,并通过具体示例展示 Ajax 在 JSF 中的应用。首先,确保安装 JDK 和支持 Java EE 的应用服务器(如 Apache Tomcat 或 WildFly)。
47 0