react修仙笔记,请问仙溪几级了?

简介: react在企业项目中已经变成了一个必不可少的UI框架,从过去早期有jquery,后面有bootstrap兴起,jquery可以说二次封装的原生js,bootstarp可以快速搭建一个精美网页,现在基本很少用bootstrap和jquery了,基本上vuejs,react,angular三分天下,国内vuejs和react居多,angular很少用

react在企业项目中已经变成了一个必不可少的UI框架,从过去早期有jquery,后面有bootstrap兴起,jquery可以说二次封装的原生jsbootstarp可以快速搭建一个精美网页,现在基本很少用bootstrapjquery了,基本上vuejsreactangular三分天下,国内vuejsreact居多,angular很少用,本文是一篇笔者关于react相关的笔记,希望看完在项目中有所思考和帮助。


在开始本文之前,主要会从以下几个方面去认识学习react


1、没有概念,用实际例子感受react核心思想

2、react数据流是怎么样,父子通信,react是如何更新数据

3、class组件与纯函数组件

4、react的状态提升

5、react组合概念

6、react设计哲学


正文开始...


class组件


react的理念就是构建UI的一个库,很大一个特征就是申明式组件化跨平台


  • 申明式
import React from "react";
import ReactDOM from 'react-dom/client';
class HelloMessage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    }
  }
  render() {
    return (
      <div>
        Hello {this.props.name}
      </div>
    );
  }
}
const root = ReactDOM.createRoot(document.getElementById('hello-example'))
root.render(<HelloMessage name="Web技术学苑" />);

从以上我们知道就是用class申明了一个HelloMessage的组件,继承了React.Component组件,然后通过root.render()挂载到dom上,我们也会发现HelloMessage这个class组件中的render中返回的就是一个jsx,这就是挂载在dom上的具体内容


纯函数组件


以上是class方式写的一个组件,但是从react16.8 版本后就出现了hook,也就是过去纯函数组件没有自己的状态,但是有了hook后,纯函数组件就可以有自己的状态了。我们完全可以用函数组件hook替代class组件,上面一段代码,如果用函数组件就是下面这样的

import React, { useState } from "react";
import ReactDOM from 'react-dom/client';
const HelloMessage = (props) => {
 const [count, setCount] = useState(0);
  return (
      <div>
        Hello {props.name}
      </div>
    );
}
const root = ReactDOM.createRoot(document.getElementById('hello-example'))
root.render(<HelloMessage name="Web技术学苑" />);


状态提升


我们知道每个组件有自己的state,如果同一个组件内部都是自己的state,那么组件之间就是互相独立,但是此时我想让一个组件输入值,也会影响另一个组件,那么此时就需要两个组件的数据依赖来源就必须提升到父组件里去,所以这就是状态提升。


我们以人民币换算美元汇率的例子加深对状态提升概念的理解

import React from "react";
class List extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0,
            price: 0,
            type: 0, // 0 人民币 1 代表美元
        }
    }
    handleAdd = () => {
        // this.setState({
        //     count: ++this.state.count
        // })
        this.setState(state => {
            return {
                ...state,
                count: state.count + 1
            }
        })
    }
    handleReduce = () => {
        this.setState(state => {
            return {
                count: state.count - 1
            }
        })
    }
    handleRmbInput = (e) => {
        const val = e.target.value;
        console.log(e)
        this.setState({
            price: val,
            type: 0
        })
    }
    handleDollInput = (e) => {
        const val = e.target.value;
        this.setState({
            price: val,
            type: 1
        })
    }
    render() {
        const { count, price, type } = this.state;
        const RmbInput = ({ price, handleChange }) => {
            return (<fieldset>
                <legend>人民币</legend>
                <input value={price}
                    onChange={handleChange} />
            </fieldset>)
        };
        const DollarInput = ({ price, handleChange }) => {
            return (<fieldset>
                <legend>美元</legend>
                <input value={price}
                    onChange={handleChange} />
            </fieldset>)
        };
        const rmbVal = type === 0 ? price : price * 7.34;
        const dollVal = type === 1 ? price : 0.14 * price;
        return (<div className="list-app" style={{ padding: '10px' }}>
            <hr />
            <button onClick={this.handleAdd}>+</button>
            <span>{count}</span>
            <button onClick={this.handleReduce}>-</button>
            <hr />
            <RmbInput handleChange={this.handleRmbInput} price={rmbVal} />
            <hr></hr>
            <DollarInput handleChange={this.handleDollInput} price={dollVal} />
        </div>)
    }
}
export default List

我们看到List这个组件返回的有RmbInputDollarInput组件,你会发现实际上这两个组件的共同特征就是都传入了两个props到子组件中,注意其中一个是传入的是方法handleChange,通常在react中数据流是单向的,所以修改传入的子组件的props,通常是通过父组件的传入子组件的回调方法去修改传入子组件的props


比如说下面这样一段伪代码


// Parant
function Parent() {
  const { name, setName} = useState("Web技术学苑");
  return (<div>
    <h1>{name}</h1>
    <Child name={name} onChangeName={val => setName(val)}/>
  </div>)
}
// Child
function Child(props) {
  return (<div>
    <input value={props.name} onChange={e => props.onChangeName(e.target.value)}/>
  </div>)
}

最后我们看下最终的效果


640 (17).png


因此一个计算汇率的功能就OK了


但是我们发现实际上RmbInputDollarInput做的事情都是非常类似的,只有名称不一样,因此我们可以将这两个组件合并成一个组件,只需传入一个参数来判断名称即可。


import React from "react";
class List extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0,
            price: 0,
            type: 0, // 0 人民币 1 代表美元
        }
    }
   ...
   render() {
        const { count, price, type } = this.state;
        // 合并成一个组件了
        const ExchangeInput = ({ price, handleChange, type }) => {
            return (<fieldset>
                <legend>{type === "RmbInput" ? '人民币' : '美元'}</legend>
                <input value={price}
                    onChange={handleChange} />
            </fieldset>)
        }
        const rmbVal = type === 0 ? price : price * 7.34;
        const dollVal = type === 1 ? price : 0.14 * price;
        return (<div className="list-app" style={{ padding: '10px' }}>
            <hr />
            <button onClick={this.handleAdd}>+</button>
            <span>{count}</span>
            <button onClick={this.handleReduce}>-</button>
            <hr />
            <ExchangeInput handleChange={this.handleRmbInput} price={rmbVal} type="RmbInput"></ExchangeInput>
            <hr/>
            <ExchangeInput handleChange={this.handleDollInput} price={dollVal} type="DollarInput"></ExchangeInput>
        </div>)
    }
}
export default List

因此从状态提升来看,react组件的state本该相互独立,但是如果想实现一个组件修改关联另一个组件修改,那么数据来源必须依赖父组件,所以也就只能把当前组件的state提升到父组件里去,从而实现了状态提升。


这里我们也发现,react提供给子组件的通信就是props,修改当前组件的state就是依赖setState,要想修改父组件数据就是通过props传入子组件的回调去修改的。


react组合


在react组合类似vue的插槽一样的概念,不过有些区别


props.children就是默认渲染所有父组件的插槽内容

import React from "react";
const Title = (props) => {
    return (<div className="title" style={{ display: 'flex' }}>
        {props.children}
    </div>)
}
const About = () => <div>
    <Title>
        <h1>Web技术学苑</h1>
        <div>Maic</div>
    </Title>
</div>
export default About;

这样你看到的结果就是下面这样的


640 (19).png

你也可以通过props做类似的vue具名插槽的功能

import React from "react";
const Title = (props) => {
    return (<div className="title" style={{ display: 'flex' }}>
        {props.children}
    </div>)
}
const Content = (props) => {
    return (<div className="content" style={{ ...props.style }}>
        {props.left}
        {props.children}
        {props.right}
    </div>)
}
const About = () => {
    const Left = () => (<div>left</div>);
    const Right = () => (<div>right</div>);
    return (<div>
        <Title>
            <h1>Web技术学苑</h1>
            <div>Maic</div>
        </Title>
        <Content 
          style={{ padding: '10px' }} 
          left={<Left />} 
          right={<Right />}
        >
          <div>center</div>
        </Content>
    </div>)
}
export default About;

我们发现Content这个组件的props可以是对象,可以是jsx,也可以是函数,当子组件用父组件的props时,我们就当它变量一样在子组件中使用,因此react中的props是相当灵活的。


640 (18).png


react哲学


react哲学[1]官方已经用了一篇文章来阐述,通篇下来,官网已经用了一个实际例子来解释react的哲学思想,总结下来,其实就是以下几点。


1、如何将复杂的UI模块拆分成更细粒度的组件,我们将一个页面拆分成组件,组件依赖数据更清晰,组件之间的耦合度更低。


2、组件的接口propsstate,要明确知道当前组件的state是应该放在顶层父组件中,还是当前自身组件


3、因为react数据流是单向的,在实现父子组件数据流双向过程中,通常用回调来传递子组件向父组件传递的数据


官方把react哲学分成了五步走概念,关于组件的拆分,其实我们心里在写代码之前就应该明白哪些组件适合独立拆分,哪些组件不用拆分,当一个页面过于复杂时,此时我们考虑拆分组件的同时,也需要考虑是否组件过度拆分带来的负担,这个因具体情况而定


总结


  • 理解react构建UI的两种方式,一种是class方式,一种纯函数组件方式
  • react数据通信,父子组件如何通信
  • 当多个组件存在互相影响时,此时得考虑状态提升,每个独立的组件状态数据依赖来源必须从顶层组件中传入,并且当需要更新props时,考虑回调函数修改
  • react中实现vue插槽的功能,也就是react的组合,props.children会默认渲染父组件插槽功能,通过props指定jsx可以可以实现具名插槽功能
  • 理解react哲学思想,让我们更灵活的运用react构建一个完整,维护性很强的web应用
  • code example[2]
相关文章
|
3月前
|
前端开发 JavaScript UED
React 基础与实践 | 青训营笔记
React 基础与实践 | 青训营笔记
52 0
|
4月前
|
前端开发 JavaScript Java
React 速通笔记
【7月更文挑战第17天】
50 1
|
前端开发 API
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
83 0
|
前端开发
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
前端学习笔记202305学习笔记第二十九天-React keep alive原理之2
78 0
|
前端开发
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之8
前端学习笔记202306学习笔记第四十八天-react-admin marmelab之7
51 0
|
6月前
|
前端开发 JavaScript
前端知识笔记(二十六)———React如何像Vue一样将css和js写在同一文件
前端知识笔记(二十六)———React如何像Vue一样将css和js写在同一文件
69 1
|
前端开发
前端笔记:React的form表单全部置空或者某个操作框置空的做法
在React框架前端开发中,经常会有弹出框的开发,涉及到弹出框,难免就会有表单。一般在关闭弹出框或者对表单联动时,往往都需要考虑对表单进行置空操作了。
98 0
|
Web App开发 前端开发 JavaScript
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
73 0
|
JavaScript 前端开发 调度
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber和虚拟dom关系
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber和虚拟dom关系
119 0
|
前端开发
前端学习笔记202307学习笔记第六十一天-react知识点串讲之11
前端学习笔记202307学习笔记第六十一天-react知识点串讲之11
61 0