消失的一两月。。。(内含React知识分享)

355 阅读11分钟

前言

亲爱的jym,好久不见了,最近写文章还是一两个月前了,一个月前还一直都处于一个 投简历 -> 面试 -> 复盘看面试题 的状态。可谓是“艰苦”啊,记得在刚过完中秋节的那个星期里,也就是九月下旬,hr估计都还沉浸在中秋的喜悦里,无法自拔,忘记了还有这么多正在投简历的同学呢😭。。。

当时由于着急,秋招已过大半,草草的就接收了深圳一家公司的实习offer(当保底),给了一个最后的入职期限,这公司money给的不多,还不包饭,这是要倒贴的节奏啊。心有不甘的我,在接下来的一两个星期里疯狂投简历,面试,看面经,争取能找到一家别让我倒贴的公司。后来也算是如愿以偿了,在国庆时也算是玩了一个假期,毕竟国庆后就要入职了。也正因为这段时间的松懈,导致后面的百度、字节二面(一面轻松,二面些许紧张,也可能是无缘大厂吧),纷纷败下阵来。

今天是入职后的第三个星期,在北京,有周末无聊的可以一起约爬山啥的,交个朋友🤝。

今天就简单的介绍了一下我的求职和入职的过程,接下来顺便把在公司没需求的时候,写的React学习文档分享给大家。让大家在看我叭叭的时候,能够学到一些知识,本文是对React由浅入深的学习,后续会更新一些更深入的React知识点(都是我在项目内看到的)。

正文

了解React是什么?

  首先React是一个用于构建用户界面的javascript库,前端React是指React.js,是Facebook推出的一个用于构建用户界面的JavaScript库。React主要用于构建UI,很多人认为React是MVC中的V(视图)。它通过Virtual DOM和diff算法提高性能,支持单向数据流。

React的几个核心概念:

  JSX

JSX实际上是JS的一个语法拓展,一般建议React搭配使用JSX语法,它可以很好的描述一个UI呈现的本质交互形式。下面这就是一个jsx。

  1. JSX存在嵌入表达式:即可以在这个JSX语法内动态绑定一些元素。就像这样:
    const name = 'Josh Perez'; 
    const element = <h1>Hello, {name}</h1>;

我们在 JSX 语法中,你可以在大括号内放置任何有效的 JavaScript 表达式。例如,2 + 2user.firstName或 formatName(user) 都是有效的 JavaScript 表达式。    

JSX可以作为一个变量赋值,也可以作为函数的返回值去使用。其语法中的属性值,可以使用"",也可以使用{ }进行赋值。

元素的渲染    

想要让一个JSX元素在页面上渲染,你需要一个由ReactDOM.createRoot()函数创建React的根节点,然后在根节点上调用render()函数进行渲染。

    const root = ReactDOM.createRoot(
        document.getElementById('root')
    ); 
    const element = <h1>Hello, world</h1>; 
    root.render(element);

  这里的element 也是 React的一个简单元素:与浏览器的 DOM 元素不同,React 元素是创建开销极小的普通对象。React DOM 会负责更新 DOM 来与 React 元素保持一致。   如果想要更新已经渲染的元素:实际上React元素是不可变对象,他就像一个单帧,一次只放映一次。大多数 React 应用只会调用一次 root.render()

  尽管每一秒我们都会新建一个描述整个 UI 树的元素,React DOM 只会更新实际改变了的内容。(这个和React虚拟DOM有关)

  组件和Props

  • 组件可以分为函数组件和类组件:

    • 函数组件:
      • 函数组件声明的时候一般对函数首字母大写,这样就被默认为一个React组件。
      • 它接收唯一带有数据的 “props”(代表属性)对象与并返回一个 React 元素。
    • class组件:
      •       使用此类进行React组件的声明,需要注意该类需要继承 React.Component,它类似于是一个声明。
    class Welcome extends React.Component {
    // 初始数据 或 接收属性值参数等
       constructor(){}
    // methods     
    
        render() {
          return <h1>Hello, {this.props.name}</h1>;     
        } 
     }
     ```   
    

组件的渲染一般都是使用render去渲染,或者在class组件内使用render函数去返回JSX元素。

  Props:

    组件无论是使用函数声明还是通过 class 声明,都绝不能修改自身的 props。这里要注意React的一个严格的规则,所有 React 组件都必须像纯函数一样保护它们的 props 不被更改。

    它的使用就是这样的:

      在class组件中,使用this.props获取组件属性参数。

      而函数组件,直接在函数上 传入一个唯一的props属性参数。

  • State状态和生命周期

    • State 与 props 类似,但是 state 是组件私有的,并且完全受控于当前组件。

    • 每次组件更新时 render 方法都会被调用,但只要在相同的 DOM 节点中渲染 <Clock /> ,就仅有一个 Clock 组件的 class 实例被创建使用。这就使得我们可以使用如 state 或生命周期方法等很多其他特性。

    •   class Clock extends React.Component {
            constructor(props) {
                super(props);    
                this.state = {date: new Date()};  
            }
            render() {
                return (
                    <div>
                        <h1>Hello, world!</h1>
                         <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
                  </div>
                );
            }
         }
      
    • 生命周期:

      • componentDidMount() 组件挂载完成后得到执行。
      • componentWillUnmount() 组件卸载之前被执行。
    •     想要实现一个持续的页面渲染,我们就可以通过声明周期的执行时间,去设置循环触发的定时器,然后在回调函数内调用setState函数去修改当前组件的状态,只要当前组件的状态发生了改变,该组件内的render函数就会重新触发,达到持续渲染的页面。

    • 当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。

事件处理机制

  React 元素的事件处理和 DOM 元素的很相似,但是有一点语法上的不同:

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。

  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

而在class组件内,可能复杂一点:它需要在构造函数内注册并修改this的指向。(为了方便还可以在定义方法时,使用箭头函数)

条件渲染

条件渲染就是可以在JSX语法内加入{ } ,在大括号内加入javascript语句都可以。

 render() {
     const isLoggedIn = this.state.isLoggedIn;
     let button;    
     if (isLoggedIn) {      
         button = <LogoutButton onClick={this.handleLogoutClick} />;    
      } else {      
          button = <LoginButton onClick={this.handleLoginClick} />;    
      }
      return (
          <div>        
              <Greeting isLoggedIn={isLoggedIn} />        
              {button}      
          </div>
       );
}
function Mailbox(props) {
    const unreadMessages = props.unreadMessages;
    return (
        <div>      
            <h1>Hello!</h1>      
            {unreadMessages.length > 0 &&        
                <h2>          
                    You have {unreadMessages.length} unread messages.        
                </h2>      
             }    
         </div>
     );
}

想要阻止组件的渲染,只需让 render 方法直接返回 null,而不进行任何渲染。

列表&Key

在组件中渲染列表,通常都是使用数组保存数据对象,然后使用数组的map方法,遍历所有的数据对象,类似于项目内的数据初始化这样。

然后在表组件内渲染这个数据可以了。 也就是说,渲染一个列表我们通常会使用数组加map方法的方式去实现:

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li key={number.toString()}>
        {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

展示列表时需要加入唯一key属性值,一个好的经验法则是:在 map() 方法中的元素需要设置 key 属性。

为什么要对列表组件加入唯一key?

主要还是由于这样可以提高React的diff算法查找和复用的效率,可以更精确的找到要更改的DOM节点。

表单的使用

  表单内的组件一般被看为是受控组件。

  在 HTML 中,表单元素(如<input>、 <textarea> 和 <select>)通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState()来更新。

  我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

form组件可以随时通过受控组件内的input输入,以及当前state所存储的表单数据。

状态的提升

由于React是单向数据流,且组件内的state都是独一无二的,它不被其他组件共享,所以当我们需要让子组件的状态被父组件所利用,这个时候就可以使用状态的声明提升方法。我们可以让子组件不使用state去存储传入组件的数据,而是直接使用参数的数据props.data。 在发生修改操作时,使用props.onxxxChange()方法,并将改变了的数据作为参数传回。

  React的高级用法:

  • Hook的特性:

    • Hook 将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据)

    • Hook 使你在无需修改组件结构的情况下复用状态逻辑。

    • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

    • Hook 在 class 内部是起作用的。但你可以使用它们来取代 class 。

      1. 在class组件内部,我们通常在constructor类构造函数内声明当前组件的state,通过this.state来创建,然后在函数组件中,我们没有this,所以不能使用this来设置组件内的状态属性,这个时候就需要使用useState hook钩子函数。
  • 常用的几种React钩子函数:

    • useState

      1. 一般用来创建响应式的数据,其使用方式如下:const [xxxstate,setxxxState] = useState(initialState)
      2. 想要修改这个变量,需要使用其第二个set方法去修改,当所修改的数值变量与之前的相同,则跳过渲染,如果不同,则重新出现渲染。
      3.       调用 useState 方法的时候做了什么?  它定义一个 “state 变量”。我们的变量叫 count, 但是我们可以叫他任何名字,比如 banana。这是一种在函数调用时保存变量的方式 —— useState是一种新方法,它与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数退出后变量就会”消失”,而 state 中的变量会被 React 保留。
    • useEffect: 被称为是副作用钩子。

      1. 当你调用 useEffect 时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。
      2. 它的作用就是一般做组件初始化处理,在如果不限制的话,在初始化第一次执行,在页面重新渲染后也执行,如果effect返回一个函数,则这个函数会在组件卸载之后执行它。
    • useContext:useContext传入的参数必须是(假如,themeContext = React.createContext(xxx) 函数返回的对象,它可以感知距离它最近上层组件,且使用了React.createContext()返回的对象提供的组件themeContext.Privider

  • useReducer:可以代替useState实现更复杂的状态管理

    •     使用方法如下:

  • useMemo:

    •   const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
      
    •       把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算。

如果没有提供依赖项数组,useMemo 在每次渲染时都会计算新的值。

  • useRef:它返回一个可变的ref对象,其.current属性被初始化为传入的参数(initialValue)。返回的ref对象在组件的整个生命周期内持续存在。

    • 当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React 绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。

    • 当一个useRef返回的对象被绑定到多个对象上时,它只会绑定一个。

    • useImperativeHandle:它可以让你在使用ref时自定义的暴露给父组件的实力值。

结尾

好了,今天的分享就到这里吧,这些只是React的一些核心概念,后续会接着看React的高级用法,感谢友友的观看,能看到这里已经很棒了。最后借用今天一个朋友的话来说,实习offer不是正式offer,所以这不是终点,还需要努力学习,寻找机会、把握机会,然后才能上岸!!!