TT的React的学习笔记

99 阅读9分钟

前言:我的前端学习之路是从Vue开始的,为了更快的形成生产力,我直接选择了Vue去学习,目前也算基本掌握了。但是我的基本功其实并没有那么优秀。所以我选择抓住机会参加了字节跳动的青训营,在青训营中重新学习前端知识,我称之重识之路。青训营授课中将会提及React,所以我也趁此机会去学习下React,以下就是我学习过程中想要记录的一些知识点又或者是感悟。

所有内容全基于本人观点,参考意义极其有限

采用对比学习,提及Vue内容均无踩一捧一的意思

「响应式系统与 React」课程笔记

React的设计思路

UI编程的痛点:

  1. 状态更新,UI不会自动更新,需要手动调动DOM更新。
  2. 欠缺代码的封装和隔离,代码层面没有组件化。
  3. 需要手动维护依赖关系,如果依赖链路过长,会出现“回调地域”。

常见的系统:

转换式系统和响应式系统

转换式系统

  • 给定输入求输出(值->值)

响应式系统

  • 监听事件,消息驱动(事件->事件)

事件->执行既定的回调->状态变更->UI更新

响应式编程特点

  1. 状态更新,UI自动更新
  2. 前端代码组件化,可复用封装
  3. 状态之间的依赖关系,只需声明即可。

组件化的准则

  1. 组件是组件的组合/原子组件
  2. 组件内拥有状态,外部不可见
  3. 父组件可将状态传入组件内部

组件设计:

  1. 组件声明了状态和UI映射
  2. 组件有Props/State两种状态
  3. 组件可以组合

React的写法

Hooks

useState 是允许你在 React 函数组件中添加 state 的 Hook useState() 方法里面唯一的参数就是初始 state useState  返回值为:当前 state 以及更新 state 的函数:[state名,setState方法]

useEffect通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。

Hook还是建议看官方文档:react.docschina.org/docs/hooks-…

如何解决状态不合理上升的问题?(状态管理库)

避免所有状态堆积。

核心思想:抽离状态到UI外部统一管理。

推荐:

  1. redux
  2. xstate
  3. mobx
  4. recoil

状态机:当前状态,收到外部事件,迁移到下一个状态。

应用级框架科普

  1. next.js
  2. modern.js
  3. Blitz

React学习笔记

React是践行组件化的一个库,它提供的是函数式的编程。

React的官方文档我认为是最好的学习工具,它非常贴心,它分别为喜欢动手和喜欢从概念学起的人提供了两种方案。

我的顺序是从 动手->概念

初识JSX

React的组件是使用JSX是一个 JavaScript 的语法扩展,它的形式如下:

const element = <h1>Hello, world!</h1>;

既不是字符串也不是html的。

元素渲染

React中想要将一个 React 元素渲染到根 DOM 节点中,只需把它们一起传入 ReactDOM.render()

我的理解:

React的元素虽然都是组件,但是不用重复的渲染他们,而只用渲染他们的顶层组件。

同时React由于diff算法的使用,使得它可以精准定位变化处,从而单独渲染变化处,而不用全部重新渲染,因此它的性能也算非常优秀的。

组件

React组件声明共有两种形式:函数组件class 组件

函数组件:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

class组件:

class Welcome extends React.Component {
  constructor(props){
    super(props);
    this.state={
        key:value,
    };
  }

  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

class组件主要是基于ES6的更新产生的。它标配一个render()它返回JSX,如果你要使用state,那你必须使用constructor,并且传入参数和super()、this.state定义是必须的。

函数组件的话,在实践教程中提到,如果你不需要state,那你可以直接使用函数组件,虽然React hook也使得函数组件可以使用state,但是那都是后续学习的内容了。

如何渲染和组合组件

其实只需要使用标签的形式就可以实现,如下:

function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name="Sara" />      <Welcome name="Cahal" />      <Welcome name="Edite" />    </div>
  );
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

这里App组件被渲染到root下,App组件中又组合了Welcome组件。

组件的渲染方式就是使用标签的形式(注意规范,组件名大写)。

标签中传入的属性将会存放在props中,通过this.props.属性名取值。

props和state

props和state是组件中最重要的两个概念,它是数据的载体。

必须注意的: props不可赋值。

props是只读的,它是只向下的。也就是说它是父组件传值的工具,子组件只能接受而不能改变。

state是组件自身属性,它可以修改、读取。

state需要注意的点:

  • 不要直接修改 State 例如,此代码不会重新渲染组件:
// Wrong
this.state.comment = 'Hello';

而是应该使用 setState():

// Correct
this.setState({comment: 'Hello'});

构造函数是唯一可以给 this.state 赋值的地方:

  • State 的更新可能是异步的 要解决这个问题,可以让 setState() 接收一个函数而不是一个对象。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数

例如,此代码可能会无法更新计数器:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
});

修改后是这样:

// Correct
this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  };
});

组件中的值如何显示

在vue中如果我们想要展示一个数据那么可以使用{{value}}直接显示。

在React中也类似如此使用{表达式}的形式进行读取值,或者调用函数。

这里需要注意的是:{}中仅能使用单独的表达式而不是大堆的代码;

比如: <h1>{add(x,y)}</h1>

//错误的例子
<h1>{
    function add(x,y){
        return x+y;
    }
}</h1>

React的事件处理

规范:

  • React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
  • 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。

例如,传统的 HTML:

<button onclick="activateLasers()">
  Activate Lasers
</button>

在 React 中略微不同:

<button onClick={activateLasers}>  Activate Lasers
</button>

使用 React 时,你一般不需要使用 addEventListener 为已创建的 DOM 元素添加监听器。事实上,你只需要在该元素初始渲染的时候添加监听器即可。

如果使用ES6的方式创建组件,并且在state声明了方法,记得一定要加bind,否则this指向会出问题。

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = {isToggleOn: true};

    // 为了在回调中使用 `this`,这个绑定是必不可少的    this.handleClick = this.handleClick.bind(this);  }

  handleClick() {    this.setState(state => ({      isToggleOn: !state.isToggleOn    }));  }
  render() {
    return (
      <button onClick={this.handleClick}>        {this.state.isToggleOn ? 'ON' : 'OFF'}
      </button>
    );
  }
}

ReactDOM.render(
  <Toggle />,
  document.getElementById('root')
);

React的生命周期

如图所示(来源):

捕获.PNG

React的生命周期相比Vue的就简单多了,在文档中举例说明了componentDidMount()componentWillUnmount()

componentDidMount() 方法会在组件已经被渲染到 DOM 中后运行。

componentWillUnmount()方法是在组件卸载前运行。

条件渲染

在Vue中条件渲染使用的是v-if,但是在React中并没有这样的封装,所以在这里只能通过if或者三目判断之类的方法返回所需要渲染的组件。

例子如下:

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {    return <UserGreeting />;  }  return <GuestGreeting />;}
ReactDOM.render(
  // Try changing to isLoggedIn={true}:
  <Greeting isLoggedIn={false} />,  document.getElementById('root'));
render() {
  const isLoggedIn = this.state.isLoggedIn;
  return (
    <div>
      {isLoggedIn? <LogoutButton onClick={this.handleLogoutClick} />
        : <LoginButton onClick={this.handleLoginClick} />      }
    </div>  );
}

如果需要阻止渲染,组件return null即可。

列表 & Key

在Vue中我们可以通过v-for实现,但是在React中是用原生方法,比如map()

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>  <li>{number}</li>);

并且和vue一样必须都拥有一个key。

表单受控组件

在vue中可以使用v-model进行双向绑定,React中必须通过绑定方法实现,例如值绑定state中的值,并且加入onChange方法绑定一个handle方法。每当用户输入信息,触发onChange,触发handle,handle进行setState操作。

例如,如果我们想让前一个示例在提交时打印出名称,我们可以将表单写为受控组件:

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: ''};
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {    this.setState({value: event.target.value});  }
  handleSubmit(event) {
    alert('提交的名字: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          名字:
          <input type="text" value={this.state.value} onChange={this.handleChange} />        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}

更多表单内容参考文档

状态提升

通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。让我们看看它是如何运作的。

这一部分如果不太理解,建议重新看一遍边做边学的[入门教程]。(react.docschina.org/tutorial/tu…)

组合 vs 继承

包含关系

如果你在写组件是不太确定是否这个组件后续有没有子组件,你可以使用{props.children}来占位。

在后续组合组件时,如果确定了,将子组件直接嵌套在标签中,就会自动替换{props.children}

例如:

function FancyBorder(props) {
  return (
    <div className={'FancyBorder FancyBorder-' + props.color}>
      {props.children}    </div>
  );
}

特例关系

如果不是简单的父子关系,而是可能临时使用如title一类的,可以使用{props.title}占位 在确定title内容后,在组件标签中传值即可实现。

React哲学

这一部分其实就是React引导思考如何开发一个优秀的SPA的分析。

简单地说就是如何写好一个React应用。

具体内容请查看官方文档,这里只写步骤。

  1. 将设计好的 UI 划分为组件层级
  2. 用 React 创建一个静态版本
  3. 确定 UI state 的最小(且完整)表示
  4. 确定 state 放置的位置
  5. 添加反向数据流

基础部分到此结束


React脚手架的使用

create-react-app中文文档

首先下载create-react-app

npm install -g create-react-app

创建一个应用

npm init react-app my-app

启动应用

npm start

react-router-dom的学习

这一部分踩坑有点多,主要是V6的更新让好多教程内容失效了。

router的声明不同vue是单独文件,React的router是在组件jsx声明的。

以下纯属个人简单理解:

它结构大概如下:

<Router>
    <Link>...
    <Routes>
    <Route>...
    </Routes>
</Router>

<Router>可以替换成# <BrowserRouter>或者# <HashRouter>,代表不同模式。

<Link>提供声明式、可访问的导航

<Route>声明路由和渲染组件的位置和渲染什么组件。必须放在<Routes>

简单小demo如下:

import React from 'react'
import './App.css';
import {BrowserRouter, Route,Link, Routes} from 'react-router-dom';
import Home from "./Componnent/Home/Home.jsx";
import Hi from "./Componnent/Hi/Hi.jsx";


function App() {
  return (
    <BrowserRouter>
    <div className="App">
      <ul>
        <li><Link to="/hi">你好</Link></li>
        <li><Link to="/home">主页</Link></li>
      </ul>
      <div>
        <Routes>
          <Route path="/hi" element={<Hi />}/>
        </Routes>
      </div>
    </div>
    </BrowserRouter>
  );
}

export default App;

这一部分还需要继续学习。。。

准备阅读文章:juejin.cn/post/702541…


To Be Continue......