react基础

220 阅读7分钟

react官网 react各个版本源码地址 bubucuo react更新日志1 react更新日志2

创建react项目

create-react-app

引入ant design

react的vscode插件

Simple React Snippets 也可以使用自定义的 在这里插入图片描述

如何修改配置文件

1.npm run eject 暴露所有的配置文件 不可逆的,在发射前需要提交git文件 2.安装react-app-rewired 这个包需要把pakage.json中的脚本配置修改为下面代码,再在根目录下创建config-overrides.js的配置

"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test",
    "eject": "react-scripts eject"
  }

React.StrictMode是什么?

StrictMode 检查项目中潜在问题。与 Fragment 一样,StrictMode 不会渲染任何可见的 UI。它为其后代元素触发额外的检查和警告。 Fragment 类似于 vue中的template

react项目文件中 为什么都要导入react包

import React from "react";
import ReactDOM from 'react-dom'
let h1 = <h1>123</h1>  //babel会编译这个 下面有编译的地址
function App() {
  return h1
}
ReactDOM.render(<App />, document.getElementById('root'))
export default App;

babel试一试地址

let h1 = /*#__PURE__*/React.createElement("h1", null, "123");
可以看到这里用到了React  所以需要导入

用到了jsx语法 所以每个文件都需要导入react包

React版本小结

 * react16
 *    开始有fiber(expireTimes 十进制一个优先级) 
 *    React.createElement(jsx):页面需要强制导入React
 *    事件委托将事件都绑定在document上,触发react事件后,也会触发用户绑定在document上的事件
 *    异步使用event前需要加上event.persit() 这里是为了提高老浏览器性能
 *    useEffect的清理函数 useLayoutEffect的清理函数 都是同步的 阻塞页面切换(如:切换标签)
 *    16.6开始有Hook
 *    16.3开始有getDerivedStateFromProps
 *    16.4 setState 和 forceUpdate也可以触发getDerivedStateFromProps
 *    
 * react17小版本
 *    优化fiber(lanes 二进制多个优先级)
 *    自动从package中引入函数调用处理jsx:页面不需要导入React
 *    事件委托将事件都绑定在root上
 *    onScroll不冒泡
 *    onFocus onBlur onClickCapture 底层切换为原生事件,和浏览器更接近
 *    移除事件池 重用了老浏览器的事件对象 异步使用event 不需要加persit了
 *    保留useLayoutEffect的清理函数同步性,把useEffect的清理函数设置为异步了执行,在屏幕更新完后执行清理
 * 
 * react18  
 *    ReactDOM.createRoot(rootDom).render(<App />)
 *    合成事件 + setTimeout0 不再能解决state同步问题
 *    原生事件也不再能解决state同步问题
 *    concurrent:早就出了,现在开始投入使用,用户自定义任务优先级且通知React,如以下
 *    useDeferredValue(text)延迟更新(模糊匹配) --- concurrent减少节流防抖的需求 
 *    [inPending,startTransition] = useTransition() 避免Suspense频繁出现loading
 *    SuspenseList可以设置多个suspense展示问题
 *    getDerivedStateFromError:之前就有了,用于捕获子组件错误如(suspense报错)

类组件 和 函数组件

函数组件使用hooks 可以替换类组件 在这里插入图片描述

受控组件和 非受控组件

受控组件 不受控组件

<input value={name} onChange={this.changeName} /> // change = e => this.setState({name:e.target.value})}
<input ref={(el)=>{this.qq = el }} /> // this.qq 就是当前dom

react常用写法

<button onClick={this.fn.bind(this)}>btn</button> //当fn中用到 this时 需要用bind绑定this
<div dangerouslySetInnerHTML={{ __html:'<h2>h2</h2>' }} /> // 渲染字符串dom
{arr.map(item => { })} //渲染数组
{bol ? a : b} // 三元运算符 类似v-if
<div id={id} className={className} style={{ height: '30px' }}>{text}</div>//花括号 可以写js语句
fn = () => {this.props.change([])} // 子组件触发 父组件传过来的方法change 间接修改父组件数据

setState注意事项

在这里插入图片描述

react生命周期

getDerivedStateFromProps和老钩子关系

生命周期 在这里插入图片描述

组件复合

在这里插入图片描述

redux

redux中文文档

在这里插入图片描述

react-redux

react-redux中文文档 在这里插入图片描述

react-router

1. react-router 2. react-router中⽂⽂档

react-router包含3个库,react-router、react-router-dom和react-router-native。 react-router提供最基本的路由功能,实际使⽤的时候我们不会直接安装react-router, ⽽是根据应⽤运⾏的环境选择安装react-router-dom(在浏览器中使⽤) 或react-router-native(在rn中使⽤)。 react-router-dom和react-router-native都依赖react-router, 所以在安装时,react-router也会⾃动安装,创建web应⽤,使⽤:

npm install --save react-router-dom
import React, { Component } from 'react';
import { BrowserRouter as Router, Link, Route, useParams, Switch, withRouter } from 'react-router-dom';
export default class RouterPage extends Component {
    render() {
        return (
            <div>
                <h3>RouterPage</h3>
                <Router>
                    {/* 添加Switch表示仅匹配⼀个 解决下面的EmptyPage*/}
                    <Switch>
                        <Link to="/">⾸⻚</Link>
                        <Link to="/user">⽤户中⼼</Link>
                        {/* 根路由要添加exact,实现精确匹配 解决/ 和 /user同时显示 */}
                        <Route
                            exact
                            path="/"
                            component={HomePage}
                        //children={() => <div>children</div>}   优先级高
                        //render={() => <div>render</div>}
                        // children 优先级高  跟其他的Route不是互斥的
                        // component 优先级中  跟其他的Route互斥的
                        // render 优先级低  跟其他的Route互斥的
                        />
                        <Route path="/user" component={UserPage} />
                        <Route component={EmptyPage} />
                    </Switch>
                </Router>
            </div>
        );
    }
}
路由重定向
import { Redirect, Route } from 'react-router'
<Redirect to={{ pathname: '/login', state: { redirect: path } }} />;

 const { redirect = '/' } = location.state || {}
动态路由
<Route path="/search/:id" children={<SearchComponent />} />
function SearchComponent(props) {
    const { id } = useParams(); // props.match.params;
    return (
      <div>
        <Link to={"/search/" + id + "/detail"}>详情</Link>
        <Route
          path={"/search/" + id + "/detail"}
          children={<DetailComponent />}
        />
      </div>
    );
}

{/* 渲染component的时候会调用React.createElement,如果使用下面这种匿名函数的形式,每次都会生成一个新的匿名的函数,
导致生成的组件的type总是不相同,这个时候会产生重复的卸载和挂载 */}
{/* 错误举例 课下自己尝试下 观察下child的didMount和willUnmount函数 */}
<Route component={() => <Child count={count} />} />  //state变化会 反复执行  挂载和卸载
<Route component={() => <FunctionChild count={count} />} />//state变化会 反复执行  挂载和卸载

{/* 下面才是正确的示范 */}
<Route render={() => <Child count={count} />} />
<Route render={() => <FunctionChild count={count} />} />

{/* children 呢  */}
<Route children={() => <Child count={count} />} />
<Route children={() => <FunctionChild count={count} />} />

部署不是根文件 服务于子文件夹 就用到了 basename

配置了BrowserRouter 如何配置服务端

纯组件

purecomponent

React.PureComponent 与 React.Component 很相似。两者的区别在于 React.Component 并未实 现 shouldComponentUpdate() ,⽽ React.PureComponent 中以浅层对⽐ prop 和 state 的⽅式来 实现了该函数。 如果赋予 React 组件相同的 props 和 state, render() 函数会渲染相同的内容,那么在某些情况下使 ⽤ React.PureComponent 可提⾼性能。

React.PureComponent 中的 shouldComponentUpdate() 仅作对象的浅层⽐较。如果对象中 包含复杂的数据结构,则有可能因为⽆法检查深层的差别,产⽣错误的⽐对结果。仅在你的 props 和 state 较为简单时,才使⽤ React.PureComponent ,或者在深层数据结构发⽣变化时 调⽤ forceUpdate() 来确保组件被正确地更新。你也可以考虑使⽤ immutable 对象加速嵌套

数据的⽐较。 此外, React.PureComponent 中的 shouldComponentUpdate() 将跳过所有⼦组件树的 prop 更新。因此,请确保所有⼦组件也都是“纯”的组件。

import React, { Component, PureComponent } from "react";
export default class PureComponentPage extends PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0,
            // obj: {
            // num: 2,
            // },
        };
    }
    setCounter = () => {
        this.setState({
            counter: 100,
            // obj: {
            // num: 200,
            // },
        });
    };
    render() {
        const { counter, obj } = this.state;
        console.log("render");
        return (
            <div>
                <h1>PuerComponentPage</h1>
                <div onClick={this.setCounter}>counter: {counter}</div>
            </div>
        );
    }
}

Hook

Hook

在这里插入图片描述

自定义hook 和 hook规则

自定义hook hook规则

<p>{useClock().toLocaleTimeString()}</p>

//⾃定义hook,命名必须以use开头
function useClock() {
	 const [date, setDate] = useState(new Date());
	 useEffect(() => {
		 console.log("date effect");
		 //只需要在didMount时候执⾏就可以了
		 const timer = setInterval(() => {
		 setDate(new Date());
	 }, 1000);	 
	 return () => clearInterval(timer);//清除定时器,类似willUnmount
	 }, []);
 	return date;
}
Hook 就是 JavaScript 函数,但是使⽤它们会有两个额外的规则:
只能在函数最外层调⽤ Hook。不要在循环、条件判断或者⼦函数中调⽤。
只能在 React 的函数组件中调⽤ Hook。不要在其他 JavaScript 函数中调⽤。(还有⼀个地⽅可
以调⽤ Hook —— 就是⾃定义的 Hook 中。)

在这里插入图片描述

hook api 之usememo 和 usecallback

hook api 索引

useMemo 把“创建”函数和依赖项数组作为参数传⼊ useMemo ,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进⾏⾼开销的计算。

import React, { useState, useMemo } from "react";
export default function UseMemoPage(props) {
	 const [count, setCount] = useState(0);
	 const expensive = useMemo(() => {
		 console.log("compute");
		 let sum = 0;
		 for (let i = 0; i < count; i++) {
			 sum += i;
		 }
		 return sum;		 
	 }, [count]);//只有count变化,这⾥才重新执⾏
	 const [value, setValue] = useState("");
	 return (
		 <div>
			 <h3>UseMemoPage</h3>
			 <p>expensive:{expensive}</p>
			 <p>{count}</p>
			 <button onClick={() => setCount(count + 1)}>add</button>
			 <input value={value} onChange={event => setValue(event.target.value)} />
		 </div>
	 );
}

useCallback 把内联回调函数及依赖项数组作为参数传⼊ useCallback ,它将返回该回调函数的 memoized 版本, 该回调函数仅在某个依赖项改变时才会更新。当你把回调函数传递给经过优化的并使⽤引⽤相等性去避 免⾮必要渲染(例如 shouldComponentUpdate )的⼦组件时,它将⾮常有⽤。

import React, { useState, useCallback, PureComponent } from "react";
export default function UseCallbackPage(props) {
	 const [count, setCount] = useState(0);
	 const addClick = useCallback(() => {
		 let sum = 0;
		 for (let i = 0; i < count; i++) {
		 	sum += i;
	 	 }
	 	 return sum;
	 }, [count]);
 	 const [value, setValue] = useState("");
	 return (
		 <div>
			 <h3>UseCallbackPage</h3>
			 <p>{count}</p>
			 <button onClick={() => setCount(count + 1)}>add</button>
			 <input value={value} onChange={event => setValue(event.target.value)} />
			 <Child addClick={addClick} />
		 </div>
	 );
}
class Child extends PureComponent {
	 render() {
		 console.log("child render");
		 const { addClick } = this.props;
		 return (
			 <div>
				 <h3>Child</h3>
				 <button onClick={() => console.log(addClick())}>add</button>
			 </div>
		 );
	 }
}

useCallback(fn, deps) 相当于 useMemo(() => fn, deps) 。