React - Andrei‘s

单页面应用,让浏览网站就像是在使用桌面应用一样;不再像之前那样点一个链接,就发一次请求,然后显示新的内容。单页面应用通过JavaScript操控页面来展示不同的内容。

React的概念

1.不直接操作DOM。React会来做这件事!

2.让构建网站变得像是搭积木。

因为一个网站是由一个个小的组件组成的,组件又可以复用,还可以分享到网上去。

3.单向数据流。(通过state里面的数据去更新组件,易于查找bug;这些数据不会流向其他组件,也不会从下往上流动;一直是从上往下流动!)

虚拟dom是一个JavaScript对象,他只会更新产生了变化的那个dom。

4.react只是一个UI库。(它只关心用户界面)

011

013

React 官方中文文档 – 用于构建用户界面的 JavaScript 库 (docschina.org)

准备工作

1.安装代码编辑器VScodeVisual Studio Code - Code Editing. Redefined

2.安装NodeJSNode.js (nodejs.org)

3.安装Vite(视频中使用的是CRA)开始 | Vite 官方中文文档 (vitejs.dev)

4.安装GitGit (git-scm.com)

028

react在什么时候会重新渲染组件?当对象完全不同的时候(状态存在对象里面)

setState这个方法就是把state变为一个不同的对象(区别于之前的state),然后react检测到了这个对象和之前那个对象在内存中处于不同的地址,就会重新渲染组件!

注意!onClick={}里面是一个回调函数!

029

确保状态更新前后,key对应的值的类型要保持相同;视频中 ,state里面name:{firstName:‘’,lastName:‘’},而setState({name:''});状态更新前是对象,状态更新后是字符串,这就会导致组件不重新渲染!

030

改写onClick中的代码:

            onClick={() => {
              this.setState({ name: "Andrei" });
              console.log(this.state);
            }}


改为

            onClick={() => {
              this.setState(
                () => {
                  return { name: "Andrei" };
                },
                () => {
                  console.log(this.state);
                }
              );
            }}

setState里面写了2个回调函数!改写之后就会显示最新的状态!

033 为什么需要加key

提高组件重新渲染的效率。

map里面的那个h1标签,相当于是一个模板,所有的数据都用了同一个模板,那么就只能通过唯一的key值来区分他们,有了key之后,如果某个值发生了变化,那就只需要去更新产生了变化的那个dom。

034SPA

ZTM.io ,如果要渲染这个页面,那就需要向服务器发请求,服务器会送回html、css、js文件来渲染页面;ZTM.io/react ,如果要渲染这个页面,需要重复刚才的步骤。

但SPA单页面应用在跳转ZTM.io/react的时候就不需要重新向服务器发送请求了!

因为第一次请求就可以拿到所有的react代码和网站代码。

035

初始数据是一个空的数组 

    this.state = {
      monsters: [],
    };

然后开始思考:

1.什么时候获取数据 when do i get the list?

2.怎么获取数据 how do i get the list?

3.数据放到哪里 where do i put the list? 放到 state 里面

react的生命周期方法,挂载就是组件第一次渲染到页面,组件第一次渲染到页面的时候就需要发起api请求,因为组件第一次挂载了就需要数据往里面填!

  componentDidMount(){
    
  }


  componentDidMount() {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json()) //转为json格式
      .then((users) =>
        this.setState(
          () => {
            return { monsters: users };
          },
          () => {
            console.log(this.state);
          }
        )
      );
  }

需要强调的一点是:当我们使用类组件(class component)的时候,需要发起api请求来加载数据,那么这个‘发请求’就要写在componentDidMount这个生命周期方法中。

036 3个方法的执行顺序

constructor()方法最先执行

render()方法第二个执行

componentDidMount()方法第三个执行

在componentDidMount()中执行了setState()这个方法,所以render()方法又执行了一次(re-render)。

这就是生命周期。

class App extends Component {
  constructor() {
    super();
    
    this.state = {
      monsters: [],
    };
    console.log('1');
  }

  componentDidMount() {
    console.log('3');
    fetch("https://jsonplaceholder.typicode.com/users")
      .then((response) => response.json()) //转为json格式
      .then((users) =>
        this.setState(
          () => {
            return { monsters: users };
          },
          () => {
            console.log(this.state);
          }
        )
      );
  }

  render() {
    console.log('2');
    return (
      <div className="w-screen h-screen bg-green-300 ">
        {this.state.monsters.map((monster) => (
          <div key={monster.id}>
            <h1 className="text-center text-3xl text-white p-2">
              {monster.name}
            </h1>
          </div>
        ))}
      </div>
    );
  }
}

如果注掉main.jsx中的严格模式:

启用严格模式:就会打印2遍

 

038 JSX中的词法有一些区别于html中的!

比如 jsx 中 className ,html中就是class,为什么?因为写在了js文件中,class是一个js内置关键词,就不能再用class了!

042 性能优化1

匿名函数就是没有使用变量来存储的函数!

这里 onChange 里面的这个匿名函数,他是一直不变的,但是每一次渲染页面都会重新加载一遍这个匿名函数,目前只有这一个函数还好,但是这样的函数多了就会影响性能,所以我们要用变量把这个匿名函数存起来!

当render()被调用的时候不用再一遍遍地加载匿名函数了!

        <input
          className="p-2 px-5 rounded-md my-5 outline-none"
          type="search"
          placeholder="search monsters"
          onChange={(e) => {
            const searchField = e.target.value.toLocaleLowerCase();
            this.setState(() => {
              return { searchField };
            });
          }}
        />


改写之后:

  onSearchChange = (e) => {
    const searchField = e.target.value.toLocaleLowerCase();
    this.setState(() => {
      return { searchField };
    });
  };

        <input
          className="p-2 px-5 rounded-md my-5 outline-none"
          type="search"
          placeholder="search monsters"
          onChange={this.onSearchChange}
        />
注意!这里onSearchChange 和render()方法平级

使用es6的新特性解构来优化代码:提高代码可读性

    const { monsters, searchField } = this.state;
    const { onSearchChange } = this;

043 文件结构

046 React 重新渲染

2种情况会导致重新渲染:

1.setState

2.props更新

047 组件

观察组件的属性,哪些属性要变,哪些属性不变

要变的属性,就通过父传子传入;不变的属性可以直接写死在组件内!

048 CSS在react里面是全局的

即使searchbox的css文件和cardlist的jsx文件处于不同的文件夹,但是cardlist依然可以使用searchbox的css文件内的类名来改变样式!

这样就相当于js组件独立,但是css不独立!

049

    // 图片来源 https://robohash.org/1?set=set2&size=180x180  
    // ?前面的1可以改,相当于变为不同的图片
    // size后面的分辨率也可以改

051 tailwindCSS 的问题!

我遇到的,如果使用了margin属性,则会导致页面上下出现白边,尤其是输入框输入数据之后!

053 类组件 vs 函数组件

类组件有生命周期方法,函数组件没有!

看看类组件的流程图:跟之前看到的一样,组件挂载,然后执行constructor方法,然后执行render方法,如果用了setState或者有新的属性,那么就再次执行render方法。这里挂载对应一个生命周期方法componentDidMount,更新对应一个生命周期方法componentDidUpdate;卸载组件对应一个生命周期方法componentWillUnmount,比如我们要跳转到别的页面,那么就会在这个方法内清除一些事件,防止内存泄漏。

054 函数组件

Sometimes when you read different guides on React,you will see people talking about functional components,going through similar methods and using similar hooks that replicate life cycles.

This is actually very misguiding because there are no life cycles when it comes to functional components.

You have to think about it in a completely different way,and the way you want to think about them is in the concept of functions and side effects.

What are side effects?

In order for us to understand side effects,we need to understand pure functions and impure functions.

函数组件没有生命周期。

055 pure functions & impure functions

纯函数和非纯函数

纯函数:函数只受到a,b参数的影响。不能产生副作用。

      const pureFunc = (a, b) => {
        return a + b;
      };
      console.log(pureFunc(2, 3));

非纯函数:函数除了受到参数a,b的影响,还要受到函数外c的影响,这就是非纯函数。

    <script>
      let c = 3;

      const funcA = (a, b) => {
        return a + b + c;
      };
      console.log(funcA(2, 3));
    </script>

副作用:会对函数作用域之外的东西产生影响。这里函数内就改变了c的值。

A side effect is when a function creates some kind of effect outside of its scope.

    <script>
      c = 3;
      const funcB = (a, b) => {
        c = a + b;
        return a * b;
      };
      console.log(funcB(2, 4), `c : ${c}`);
    </script>

函数组件的优点是可以预测的。

react可以写纯函数组件,用hooks创建非纯函数,所以就会产生副作用。

056 函数组件中的state

之前类组件的state是一个对象,里面存了很多数据;但是函数组件是用useState来注册的,每一条数据对应一个useState,并且可以是任何数据类型!

057 函数组件的渲染和重渲染

当props更新或者state改变的时候,整个函数会从上到下执行,一整个重新渲染!

这里需要注意的是!!setState并不能触发重渲染,而是因为state的值改变了才会触发重渲染!(如果setState里面还是以前的那个值,则不会触发重渲染!)

058 不可以把fetch直接写在函数组件内!

这样写会导致无限循环,最后使浏览器崩溃!

虽然拿到的数据是相同的,但是每一次请求到的数据在内存中都是不同的 !所以这种‘不同’会让setState生效,然后重新渲染整个函数组件,然后就会导致无限循环!

.

所以,当我们需要发送请求的时候,就需要副作用-side effect,在函数组件中是 useEffect()。

a side effect is some behavior that trigger from our functions that affects something that exists outside of the scope of the function.

副作用是函数内触发的某些行为,这些行为会影响到存在于函数作用域外的事物。

当我们 修改或者依赖 存在于函数作用域外的的某些值的时候,就要用到useEffect。

任何fetch请求都是副作用!Any fetch call is a side effect.

059 useEffect

useEffect方法内,第一个参数是回调函数,第二个参数是数组。

回调函数内就是我们希望发生的事情(副作用写在这个函数内),我们的请求就写在这个回调函数内。

数组里面写依赖,每当这个数组内的依赖变化的时候,回调函数就重新执行一次。

注意!当我们第一次加载函数组件的时候,这个回调函数会自动执行一次。

  useEffect(() => {
    effect
    return () => {
      cleanup
    };
  }, [input]);

这里我们只想要第一次加载的时候获取数据,所以数组内不写任何依赖! 

当一个值需要依赖另一个值而产生变化的时候,也要用到副作用,否则就会降低程序的性能!

063 dom和虚拟dom 

Reflow 重排

真实dom中,移除或更新节点或者dom,程序计算代价很高!

所以react把真实dom树映射了一份在JavaScript中,这就是虚拟dom;真实dom可以被用户看见,虚拟dom可以用来对比,哪些地方改变了。

react会把虚拟dom会创建 2份,第一份虚拟dom快照就是最开始没有发生变化时候的样子,第二份虚拟dom就会去检测变化,然后第二份发生了变化的地方会更新第一份虚拟dom,最后第一份虚拟dom会去更新真实dom。

065 React 的jsx原理

 JSX让代码的可读性提高了,写出来更像html文件的内容了,而不是这样createElement。

ReactDom就是把react代码和真实dom连接起来了。

React让我们可以用JSX的形式写html代码以及构建组件。

066

067 重绘 Repaint

元素的外观改变

071 GitHub

GitHub - ZhangMYihua/crwn-clothing-v2: Version 2 of Crwn-Clothing!

fork 可以把别人的项目 复制 到自己的仓库里面,这样就可以使用push功能了!

main分支 是我们最终发布项目的分支

因为现在只有我们自己一个人操作这个代码库,所以我们不用去更新混合策略Merge Strategy

076 Sass

1.在项目中安装sass ,注意!需要先安装node

npm install -g sass

2.创建sass文件,sass文件的扩展名是

.scss

3.使用sass的 嵌套 特性改写普通css

普通css:很长的选择器

改写成sass:嵌套

 077 css in jsx

key这个属性应该放在map那里!Key need to put in the place where we actually call the map.

078 完成了一部分任务之后,就可以提交代码了

079 

package-lock这个文件为什么会产生?

他是由npm或者yarn这种包管理器生成的,为了让所有项目成员锁定在同样的依赖版本,让项目正确运行。

082 Router

在main.jsx中引入BrowserRouter:imbr

然后用这个组件包裹整个App组件

import { BrowserRouter as Router } from "react-router-dom";
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter as Router } from "react-router-dom";
import App from "./App";
import "./index.css";

ReactDOM.createRoot(document.getElementById("root")).render(
  <React.StrictMode>
    <Router>
      <App />
    </Router>
  </React.StrictMode>
);
      <Routes>
        <Route path="/home" element={<Home />} />
      </Routes>

嵌套路由

先把嵌套的形式写好,shop嵌套在home里面;此时页面不会有显示!

      <Routes>
        <Route path="/home" element={<Home />}>
          <Route path="shop" element={<Shop />} />
        </Route>
      </Routes>

然后去home组件里面告诉嵌套的那个组件实际上应该放在哪里;使用Outlet组件

import React from "react";
import { Outlet } from "react-router-dom";

const Home = () => {
  return (
    <div>
      Home
      <Outlet />
    </div>
  );
};

export default Home;

index属性,可以让 / 这个路由直接就显示嵌套的home组件;

限制:

1.home组件必须位于第一个;他是第一个嵌套组件

2.写了index这个属性,就不能写path属性了!!否则不会生效!

085 Fragment 标签  Link标签

import React, { Fragment } from "react";
import { Outlet, Link } from "react-router-dom";

const Navigation = () => {
  return (
    <Fragment>
      <div className="bg-slate-500 text-center text-white p-5 flex justify-between">
        <Link to={'/'}>
          <div>Logo</div>
        </Link>
        <div>
          <Link
            to={"/shop"}
            className="p-2 border border-white rounded-md hover:bg-slate-600 transition-all"
          >
            SHOP
          </Link>
        </div>
      </div>
      <Outlet />
    </Fragment>
  );
};

export default Navigation;

088 

CRUD

登录

数据库

token

092

数据在数据库中的样子

102 

这里面用了Switch

103 在第三级,有多个组件需要用到user data

这个时候我们需要把user data放在app组件内,这样传递下去,那些组件都可以共用这个数据;但是问题是,中间第二层级的组件并不需要用到这些数据,那么就会造成代码冗余。

 

最完美的做法是可以直接把user data直接传递到需要用到它的组件中!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值