# react-demo **Repository Path**: hao_ran_chao/react-demo ## Basic Information - **Project Name**: react-demo - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-12-20 - **Last Updated**: 2022-01-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## React 创建(周老师) 1. 创建开发环境:npx create-react-app 项目名称 2. 如果报错,清除 npx 缓存后再试: npm -g uninstall create-react-app || npm cache clean --force ## ReactDOM.render 的作用 - 把 React 元素渲染到一个 dom 元素上 ```js ReactDOM.render( [React Element],[DOM element] ); ``` ## 什么是 jsx - jsx 是 React.creacteElement 的语法糖。 - React.createElement 用法: ```js React.creacteElement( string|element, [propsObject], [chuldren...] ) ``` - React.createElement 的参数 - 在 JSX 中使用表达式,将表达式写在{}里 和字符串模版的${}里的内容类似,也必须是一个表达式,不能是多个表达式 ```js function SubmitButton() { const buttonLabel = '提交' return } ``` - {}中的表达式可以是:字符串、数字、jsx 元素、布尔类型、function、null、undefined、symbol - 组件的注意事项? 1. 组件的名字必须首字母大写,这样 react 才能区分写的 tag 名字是 html 本来的元素,或是一个自定义组件 2. 组件元素的 tag 必须闭合 3. 组件中原 html 元素的属性,如果是两个单词组成的属性应该用驼峰表达 - style 属性的处理? 在 html 中元素的 style 属性是一个字符串类型;在 JSX 中需要写为对象 ```js

``` - html 属性的处理? 1. 驼峰属性除了 class 要写成 className,for 也要写成 htmlFor 因为 class 和 for 都是 Javascript 的关键字 2. 特殊内容会自动做 html encode,避免 xss 攻击 3. 如果你不想使用转义,可以用 **dangerouslySetInnerHTML**属性设置,它的内容是一个 object,里面 key 为\_\_html 用于设置 html ```js function createMarkup() { return { __html: "哈哈" }; } function MyComponent() { return

; } ``` ## 如何向自定义的 React 组件传递属性? - React 声明组件的方式? - 函数组件和类组件 - 函数组件传递数据的方式有? - 父向子传递数据:通过属性 ```js function Person(props) { return {props.name}; } const person = ; ``` - 用解构声明属性:如果调用自定义组件的地方传递了它没有声明的属性也不会处理。 ```js function Person({ name, age = 18 }) { return {props.name}; } ``` - **children 属性**,children 可能是一个节点(node),节点包括了元素(element)和 string,也可能是一个节点的数组 - children 的相关函数 ```js React.Children.count(children); // 数量 React.Children.only(children); // 判断children是不是 // 只有一个 // 如果不是就报错 React.Children.toArray(children); // 转换为数组 ``` - 子组件向父组件通信:通过回调函数 - 渲染数组的方式? - 数组元素转换为 JSX 元素,可以很方便的用数组的 map 方法实现 **转换出的数组每一个 JSX 元素,要有一个 key 属性,key 值必须为一个唯一值,一般用数组元素里的 ID 属性,如果没有此类属性就用序号(index)** - 总结:函数组件的创建: 1. 函数组件一个(纯)函数 2. 参数只有1个,类型是Object,key就是组件的属性名称 3. 属性值可以是任意值:包括所有基本类型,引用类型,null,undefined,函数或JSX元素 4. 特殊属性 children(children指组件所包含的内容) 5. 返回值是JSX元素(单元素,不要返回数组)或null ## Rect:prpos&state - state 和 props 的区别? - state 是内部的状态,由组件自身维护(没必要让父元素管理的属性),可以修改 - props 是组件外部传入进来的,组件不可以修改 props 上的值 - state 怎么初始化? 1. state 在构造方法内部初始化(所以首先要了解类组件的构造方法怎样声明) 2. state 在类的成员变量声明处初始化(更好的解决方案,构造方法都不用写了) ```js class Counter extends React.Component { state = {counter: 0} render() {...} } ``` - 继承中构造方法如何使用? - 子类继承父类,子类不必须要声明构造方法; - 但如果声明了构造方法就必须调用父类的构造方法 ## React 函数组件和类组件 - 类组件: 1. 为什么需要类组件? - 类组件有状态,函数组件没有 - 类组件有生命周期,函数组件没有 2. 类组件的定义? - 继承自 React.Component ```js import React from 'react' class MyComponent extends React.Component { ... } ``` - render 是必须要声明的方法,render 必须返回一个节点(node)或 null。 ```js class MyComponent extends React.Component { render() { return
MyComponent
; // 或 // return 1 // return null } } ``` 3. 类组件的构造方法? ```js constructor(props); ``` ```js class MyComponent extends React.Component { constructor(props) { super(props); // 初始化props this.state = {speed: 0}; // 初始化state this.handleClick = this.handleClick.bind(this); // 初始化其他属性 } } ``` 4. 在类组件中如何使用 props? ```js ; class MyComponent extends React.Component { render() { return
{this.props.text}
; } } ``` 5. state 如何状态管理? 对应 props 使用 this.props 访问属性,state 使用 this.state 访问状态 6. state 的定义? - state 上包含了可能变化的数据; - state 由用户自定义; - 它是一个普通的 JavaScript 对象 7. state 是什么类型数据? this.state 是一个 Object 类型/null,不能是简单类型 8. 类组件里的 constructor 中应做什么事情? - 初始化 state - 初始化其他属性 9. 不要在类组件里的 constructor 中做什么事? - 使用 setState - 监听事件 - 开启计时器 - 发起异步请求 - ... 10. 如何修改 state 状态? 首先 state 必须是一个对象,不能是简单类型(字符串,数字,布尔类型) 其次 state 必须通过 setState 方法修改,不能直接赋值 ```js this.state.value = 1 // × this.state = {value: 1} // × this.setState({value:1}) // √ ``` 11. 类组件上事件处理函数的 this 问题? ```js class MyComponent extends React.Component { handleClick() { this.setState({...}) } render() { // 🙅将会报错! // 因为this.handleClick作为函数赋值给其他变量 // 在调用该函数的时候没有上下文,this就是undfined! return } } ``` 12. state 和 setState 函数的区别? - state: - 首先 state 的型态是这样的 Javascript 对象 (“state 上的值”是指 state 对象上第一层级 key 的 value) - state 上的值必须由 setState 修改(原因是通过 setState 修改后才能触发 render 重新刷新 如果直接修改,虽然 state 上的数据改变了,但并不会 render,所以前端也没有体现) - state 上的值如果发生改变,则会触发 render(界面刷新) - setState: - setState 函数无返回值 - setState 使用“浅合并”而非“深合并”(因此 state 值如果想发生“改变”必须用复制的方式,合并仅限于第一层) - setState 的效果是异步的,意思就是说执行后并不是马上会修改 state 上的那个值,因此,**在一次事件循环中一个组件多次调用 setState**,结果会合并成一次执行 13. setState 有几个参数 - 第一个参数是一个 Object,Object 的内容是你想修改 state 上的部分值。 ⚠️ 修改后 state 的值是 setState 传入 Object 和原 state 值的合并值。 - 第二个参数(非必填),是一个回调函数,它会在 render 结束后执行,也就是在 state 在这次 setState 真正生效后执行。 14. 什么值不应记在 state 上? 跟 render 无关的值,比如计时器的 id,直接用类似 this.timer 的变量保存即可 ## React 生命周期 1. 深入 react 生命周期 (星号表示常用的生命周期) - 挂载: - **constructor(props):构造方法** - 初始化 - ⚠️ 注意不要在构造方法里执行 setState - 应该在 constructor 里初始化 state 对象 - 构造函数是唯一可以给 this.state 赋值的地方。 ```js ⚠️ 不要写这样的代码 constructor(props){ super(props); //不要用props初始化state this.state={ value : this.props.value } } ``` 原因:如此做毫无必要(你可以直接使用 this.props.color),同时还产生了 bug(更新 prop 中的 color 时,并不会影响 state)。 只有在你刻意忽略 prop 更新的情况下使用。此时,应将 prop 重命名为 initialColor 或 defaultColor。必要时,你可以修改它的 key,以强制“重置”其内部 state。 - static getDerivedStateFromProps(props,state):不管原因是什么,都会在每次渲染前触发此方法。 getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。 - 它应返回一个对象来更新 state - 如果返回 null 则不更新任何内容 - **render():方法是 class 组件中唯一必须实现的方法** - this.props 和 this.state 发生变化时render会调用,有以下种类返回值: - React 元素 - 数组或fragments - Portals - 字符串或数值类型 - 布尔类型或 null。 如test && - render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。 - **componentDidMount(): 在组件挂载后(插入 DOM 树中)立即调用。** 依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。 这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在 componentWillUnmount() 里取消订阅 - 可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。 - 更新: - static getDerivedStateFromProps(props,state) - shouldComponentUpdate(nextProps, nextState): - 当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用. - 根据props/state值运算是否需要运行render - 返回值默认为 true. - 首次渲染或使用 forceUpdate() 时不会调用该方法。 - **render():** - getSnapshotBeforeUpdate(): - getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。 - 应返回 snapshot 的值(或 null)。 - 返回值会进入 componentDidUpdate 作为它的第三个参数传入 - **componentDidUpDate(prevProps, prevState, snapshot):会在更新后会被立即调用** - prevProps/prevState 指上次更新前的 props 和 state - 首次渲染不会执行此方法。 - 可以在 componentDidUpdate() 中直接调用 setState(),但请注意 ⚠️ 它必须被包裹在一个条件语句里,否则会造成死循环 - ⚠️ 如果 shouldComponentUpdate() 返回值为 false,则不会调用 componentDidUpdate()。 - 销毁: - **componentWillUnMount():在组件卸载及销毁之前直接调用。** - 在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。 - componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。 - forceUpdate(): - 强制组件调用 render(); - 跳过 shouldComponentUpdate() 应该避免使用 forceUpdate(),尽量在 render() 中使用 this.props 和 this.state。 2. getDerivedStateFromProps 什么时候使用派生 state? getDerivedStateFromProps 的存在只有一个目的:让组件在 props 变化时更新 state。比如 props 的 offset 变化时,修改当前的滚动方向和根据 props 变化加载外部数据。 派生状态会导致代码冗余,并使组件难以维护。 尽量使用其他方法代替 3. shouldComponentUpdate 的使用场景? - 此方法仅作为性能优化的方式而存在。 - 处理不当容易产生 bug - 优先考虑使用内置的 PureComponent 组件 - PureComponent 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。 4. componentDidUpdate 使用场景? - 当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。 ## 错误边界 Error boundaries 1. Error boundaries: React 组件它会在其子组件树中的任何位置捕获 JavaScript 错误,并记录这些错误,展示降级 UI 而不是崩溃的组件树。Error boundaries 组件会捕获在渲染期间,在生命周期方法以及其整个树的构造函数中发生的错误。 2. 定义了哪些生命周期方法? - static getDerivedStateFromError() - componentDidCatch() 3. 使用场景? - 仅使用 Error boundaries 组件来从意外异常中恢复的情况; - 不要将它们用于流程控制。 4. static getDerivedStateFromError(error) - 此生命周期会在后代组件抛出错误后被调用。 - 它将抛出的错误作为参数,并返回一个值以更新 state - ⚠️ getDerivedStateFromError() 会在渲染阶段调用,因此不允许出现副作用。 如遇此类情况,请改用 componentDidCatch()。 5. componentDidCatch(error, info)在后代组件抛出错误后被调用,接收两个参数: - error —— 抛出的错误。 - info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。 componentDidCatch() 会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况。 ## 事件对象 - React 使用“合成事件(SyntheticEvent)”对象来描述事件 - 事件处理函数中会传递 SyntheticEvent 实例对象作为 event,它是浏览器的原生事件的跨浏览器包装器。 除兼容所有浏览器外,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation() 和 preventDefault()。 事件处理函数中会传递 SyntheticEvent 实例对象作为 event,它是浏览器的原生事件的跨浏览器包装器。 除兼容所有浏览器外,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation() 和 preventDefault()。 - 如果需要原来的 event 对象,可以使用 event.nativeEvent 访问 - **重点:onChange 事件** ## Refs 1. Refs 的意思是指“指向” 2. Refs 使用场景? - 管理焦点,文本选择或媒体播放。 - 触发强制动画。 - 集成第三方 DOM 库。 3. Refs 创建:React.createRef() ```js class MyComponent extends React.Component { constructor(props) { super(props); this.myRef = React.createRef(); } render() { return
; } } ``` 4. 访问 Refs: ```js const node = this.myRef.current; ``` - 当 ref 属性用于 HTML 元素,this.myRef.current 为该 html 元素的 dom 元素 - 当 ref 属性用于 class 组件,this.myRef.current 指向该组件的元素实例 - ⚠️ 对函数组件不能用 ref 属性 5. DOM 元素节点的例子 - ref 值的改变 - 挂载时给 current 属性传入值 - 卸载时给 current 属性传入 null - ref 会在 componentDidMount 或 componentDidUpdate 生命周期钩子触发前更新 6. class 组件元素的 ref 例子 - 回调式 Refs 更精细的控制 refs 的设置和解除 ```js class CustomTextInput extends React.Component { constructor(props) { super(props); this.textInput = null; this.textInputRef = (element) => { this.textInput = element; }; } render() { return (
); } } ``` - ⚠️ 不要直接在 ref 的地方写匿名回调函数,会造成性能降低,造成每次渲染都会重新运行该方法。 7. 子组件的 dom 元素 ref 给父级 ```js function CustomTextInput(props) { return (
); } class Parent extends React.Component { render() { return (this.inputElement = el)} />; } } ``` - ⚠️ref 和 key 一样不是 props ## React-Router 1. 安装: yarn add react-router-dom; 2. 路由的原理? - 通过改变 URL,在不重新请求页面的情况下,更新页面视图 3. 路由的实现方式: - hash 模式:通过#后面的内容更改,触发 hashchange 事件,实现路由的切换。 - history 模式:通过 pushState 和 replaceState 切换 url,触发 popState,实现路由切换,需要后端配合。 4. hash 和 history 两种模式: - hash 模式: **HashHistory.push()** 将新的路由添加到浏览器访问的历史的栈顶, **HasHistory.replace()**替换到当前栈顶的路由 - history 模式: **window.history.pushState(stateObject, title, URL)** **window.history.replaceState(stateObject, title, URL)** - 包括 back,forward,go 三个方法,对应浏览器的前进 forward,后退 back,跳转 go 操作: - history.go(-2);//后退两次 - history.go(2);//前进两次 - history.back(); //后退 - hsitory.forward(); //前进 5. React 路由的三大组成部分 - 容器:BrowserRouter - 导航:NavLink - 路线:Route(配置,渲染) 6. React BrowserRouter 和 HashRouter 的区别? - 区别: BrowserRouter 和 HashRouter 都可以实现前端路由的功能 BrowserRouter 实现的是单页面的路由切换 HashRouter 实现的是全局路由切换 7. Link 和 NavLink - **NavLink 当前选中会增加默认一个 classname 而 link 直接就是链接跳转** - NavLink 是的一个特定版本,会在匹配上当前的 url 的时候给已经渲染的元素添加参数,组件的属性有 · activeClassName(string):设置选中样式,默认值为 active · activeStyle(object):当元素被选中时,为此元素添加样式 · exact(bool):为 true 时,只有当导致和完全匹配 class 和 style 才会应用 · strict(bool):为 true 时,在确定为位置是否与当前 URL 匹配时,将考虑位置 pathname 后的斜线 · isActive(func)判断链接是否激活的额外逻辑的功能 8. link 上的属性: - to: - 可以是 string ```js 关于我们 按名称排序 ``` - 可以是 object ```js 课程 ``` - 可以是 function ```js ({ ...location, pathname: "/courses" })} /> `${location.pathname}?sort=name`} /> ``` - replace 是 bool 类型,替换 history 里的记录 ```js 课程 ``` - component 属性用于渲染自定义 Link 样式 ```js const FancyLink = React.forwardRef(({ navigate, ...props }, ref) => { const handleClick = (e) => { e.preventDefault(); navigate(); // 执行跳转 }; return ( 💅 {props.children} ); }); ``` - 另外可以使用其他一切 html 上 a 标签的属性 className | style | title ... 9. 路由组件的路由属性: - match - location - history - 其他属性 - exact 是否确切匹配(默认 false) - strict 是否严格匹配(带不带/,默认 false) - sensitive 是否区分大小写(默认 false) 10. 确切匹配和严格匹配 - 确切: ```js ``` - 严格: ```js ``` ⚠️ 如果想不包含结尾的/,exact 必须也为 true,因为 exact 的优先级比 strict 高,如果 exact=false 11. Route 中的 render 和 childer ```js

render

} />

children

} /> ``` 两者很相似,都是用匿名函数直接作为参数 - 区别: - render - children:无论是否匹配都会显示,主要用于路由动画 12. NavLink 组件基本同 Link 组件的属性,提供一些专门用于显示导航的链接的属性 - exact/strict 同 Route - activeClassName: string 激活状态的 class 名 ```js 常见问题 ``` - className: string | func ```js "nav-link" + (!isActive ? "unselected" : "")} > 常见问题 ``` - activeStyle: object 激活状态的内联样式 ```js 常见问题 ``` - style: object | func - isActive: func : 判断是否是激活状态 13. React 路由组件 - Switch 组件:灵感来源于 switch...case 语句 Switch 中的 Route 有多条,只能匹配一个,谁先匹配到后面的就失效了 - 用 Switch 包裹后,哪个路由先匹配就显示哪个 ```js render () { return } ``` - Redirect 组件:当渲染 Redirect 组件时会跳转到 Redirect 上配置 location 上,新的 location 会覆盖旧的(不在 history 中产生新记录) - from: string:这个属性只有 Redirect 在 Switch 组件中才有用,用于匹配生效 ```js ``` - Prompt 组件: - 使用场景:表单填了一般还没有提交或保存,用户想要离开当前页面时,弹出提示框,试图阻止用户离开 ```js ``` - 属性: message: string message: func when: bool :但条件为 true 的时候才显示 message 14. location.assign 与 location.replace 的区别? - window.location.assign(url) :加载 URL 指定的新的 HTML 文档。 就相当于一个链接,跳转到指定的 url,当前页面会转为新页面内容,可以点击后退返回上一个页面。 - window.location.replace(url) : 通过加载 URL 指定的文档来替换当前文档 ,这个方法是替换当前窗口页面,前后两个页面共用一个 窗口,所以是没有后退返回上一页的 ## Hooks 1. Hooks 它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 2. Hook 使用规则? 1. 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。 2. 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。 3. 另外,自定义 Hook 的命名也要用 use 开头 3. 计算机科学中的副作用 指函数调用除了返回值以外,对函数内部环境外一些状态或变量值产生了修改,称这个函数产生了副作用。