「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 元素。

相关文章
|
30天前
|
前端开发 JavaScript API
基于React的简易REST API客户端设计与实现
基于React的简易REST API客户端设计与实现
21 3
|
1月前
|
JavaScript 前端开发 API
深入浅出:Vue 3 Composition API 的魅力与实践
【2月更文挑战第13天】 本文将探索 Vue 3 的核心特性之一——Composition API。通过对比 Options API,本文旨在揭示 Composition API 如何提高代码的组织性和可复用性,并通过实际案例展示其在现代前端开发中的应用。不同于传统的技术文章摘要,我们将通过一个具体的开发场景,引领读者步入 Composition API 的世界,展现它如何优雅地解决复杂组件逻辑的管理问题,从而激发读者探索和运用 Vue 3 新特性的热情。
21 1
|
2月前
|
数据采集 监控 算法
利用大数据和API优化电商决策:商品性能分析实践
在数据驱动的电子商务时代,大数据分析已成为企业提升运营效率、增强市场竞争力的关键工具。通过精确收集和分析商品性能数据,企业能够洞察市场趋势,实现库存优化,提升顾客满意度,并显著增加销售额。本文将探讨如何通过API收集商品数据,并将这些数据转化为对电商平台有价值的洞察。
|
2月前
|
人工智能 NoSQL Serverless
基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
本文主要分享了自己基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
469 6
基于函数计算3.0 Stable Diffusion Serverless API 的AI艺术字头像生成应用搭建与实践的报告
|
3天前
|
前端开发 JavaScript API
React的Context API:全局状态管理的利器
【4月更文挑战第25天】React的Context API解决了深层组件间状态共享的难题,提供全局状态管理方案。通过`Provider`和`Consumer`组件,或结合`useContext` Hook,实现状态在组件树中的传递。最佳实践包括避免过度使用,分离逻辑,以及在必要时与Redux或MobX结合。Context API简化了数据传递,但需谨慎使用以保持代码清晰。
|
29天前
|
XML JSON 安全
谈谈你对RESTful API设计的理解和实践。
RESTful API是基于HTTP协议的接口设计,通过URI标识资源,利用GET、POST、PUT、DELETE等方法操作资源。设计注重无状态、一致性、分层、错误处理、版本控制、文档、安全和测试,确保易用、可扩展和安全。例如,`/users/{id}`用于用户管理,使用JSON或XML交换数据,提升系统互操作性和可维护性。
18 4
|
1月前
|
消息中间件 缓存 API
微服务架构下的API网关性能优化实践
在现代的软件开发中,微服务架构因其灵活性和可扩展性被广泛采用。随着服务的细分与增多,API网关作为微服务架构中的关键组件,承担着请求路由、负载均衡、权限校验等重要职责。然而,随着流量的增长和业务复杂度的提升,API网关很容易成为性能瓶颈。本文将深入探讨API网关在微服务环境中的性能优化策略,包括缓存机制、连接池管理、异步处理等方面的具体实现,旨在为开发者提供实用的性能提升指导。
|
1月前
|
缓存 负载均衡 监控
构建高效微服务架构:API网关的作用与实践
【2月更文挑战第31天】 在当今的软件开发领域,微服务架构已成为实现系统高度模块化和易于扩展的首选方法。然而,随着微服务数量的增加,确保通信效率和管理一致性变得尤为重要。本文将探讨API网关在微服务架构中的核心角色,包括其在请求路由、安全性、负载均衡以及聚合功能方面的重要性。我们将通过具体案例分析,展示如何利用API网关优化后端服务,并讨论实施过程中的最佳实践和常见挑战。
|
1月前
|
搜索推荐 数据挖掘 API
1688商品详情API在电商平台中的应用与实践
随着电子商务的迅猛发展,越来越多的商家选择利用API(应用程序编程接口)来提升其在线业务的效率和用户体验。特别是在商品信息展示方面,1688商品详情API作为连接商家和消费者的重要桥梁,扮演着至关重要的角色。本文将深入探讨1688商品详情API的功能、应用场景以及如何通过该API提高电商平台的商品信息展示质量。
|
1月前
|
JSON API 数据格式
构建高效Python Web应用:Flask框架与RESTful API设计实践
【2月更文挑战第17天】在现代Web开发中,轻量级框架与RESTful API设计成为了提升应用性能和可维护性的关键。本文将深入探讨如何使用Python的Flask框架来构建高效的Web服务,并通过具体实例分析RESTful API的设计原则及其实现过程。我们将从基本的应用架构出发,逐步介绍如何利用Flask的灵活性进行模块化开发,并结合请求处理、数据验证以及安全性考虑,打造出一个既符合标准又易于扩展的Web应用。
659 4