React 中 keys 的作用是什么?

React 中 keys 的作用是什么?

Keys 是 React 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识。在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在React Diff 算法中 React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性。

调用 setState 之后发生了什么?

在代码中调用 setState 函数之后,React 会将传入的参数对象与组件当前的状态合并,然后触发所谓的调和过程(Reconciliation)。经过调和过程,React 会以相对高效的方式根据新的状态构建 React 元素树并且着手重新渲染整个 UI 界面。在React 得到元素树之后,React 会自动计算出新的树与老树的节点差异,然后根据差异对界面进行最小化重渲染。在差异计算算法中,React 能够相对精确地知道哪些位置发生了改变以及应该如何改变,这就保证了按需更新,而不是全部重新渲染。

react 生命周期函数

• 初始化阶段:
o getDefaultProps:获取实例的默认属性
o getInitialState:获取每个实例的初始化状态
o componentWillMount:组件即将被装载、渲染到页面上
o render:组件在这里生成虚拟的 DOM 节点
o componentDidMount:组件真正在被装载之后
• 运行中状态:
o componentWillReceiveProps:组件将要接收到属性的时候调用
o shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回 false,接收数据后不更新,阻止 render 调用,后面的函数不会被继续执行了)
o componentWillUpdate:组件即将更新不能修改属性和状态
o render:组件重新描绘
o componentDidUpdate:组件已经更新
• 销毁阶段:
o componentWillUnmount:组件即将销毁shouldComponentUpdate 是做什么的,(react 性能优化是哪个周期函数?)
shouldComponentUpdate 这个方法用来判断是否需要调用 render 方法重新描绘dom。因为 dom 的描绘非常消耗性能,如果我们能在 shouldComponentUpdate 方法中能够写出更优化的 dom diff 算法,可以极大的提高性能。

为什么虚拟 dom 会提高性能?(必考)

虚拟 dom 相当于在 js 和真实 dom 中间加了一个缓存,利用 dom diff 算法避免了没有必要的 dom 操作,从而提高性能。用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM树,插到文档当中当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异把 2 所记录的差异应用到步骤 1 所构建的真正的DOM 树上,视图就更新了。

react diff 原理(常考,大厂必考)

• 把树形结构按照层级分解,只比较同级元素。
• 给列表结构的每个单元添加唯一的 key 属性,方便比较。
• React 只会匹配相同 class 的 component(这里面的 class 指的是组件的名字)
• 合并操作,调用 component 的 setState 方法的时候, React 将其标记为 dirty.到每一个事件循环结束, React 检查所有标记 dirty 的 component 重新绘制.
• 选择性子树渲染。开发人员可以重写 shouldComponentUpdate 提高 diff 的性能。

React 中 refs 的作用是什么?

何为受控组件(controlled component)

在 HTML 中,类似 , 和 这样的表单元素会维护自身的状态,并基于用户的输入来更新。当用户提交表单时,前面提到的元素的值将随表单一起被发送。但在 React 中会有些不同,包含表单元素的组件将会在 state 中追踪输入的值,并且每次调用回调函数时,如 onChange 会更新 state,重新渲染组件。一个输入表单元素,它的值通过 React 的这种方式来控制,这样的元素就被称为"受控元素"。

何为高阶组件(higher order component)

高阶组件是一个以组件为参数并返回一个新组件的函数。HOC 运行你重用代码、逻辑和引导抽象。最常见的可能是 Redux 的 connect 函数。除了简单分享工具库和简单的组合,HOC 最好的方式是共享 React 组件之间的行为。如果你发现你在不同的地方写了大量代码来做同一件事时,就应该考虑将代码重构为可重用的HOC。

为什么建议传递给 setState 的参数是一个 callback 而不是一个对象

因为 this.props 和 this.state 的更新可能是异步的,不能依赖它们的值去计算下一个state。

除了在构造函数中绑定 this,还有其它方式吗

你可以使用属性初始值设定项(property initializers)来正确绑定回调,create-reactapp 也是默认支持的。在回调中你可以使用箭头函数,但问题是每次组件渲染时都会创建一个新的回调。

(在构造函数中)调用 super(props) 的目的是什么

在 super() 被调用之前,子类是不能使用 this 的,在 ES2015 中,子类必须在constructor 中调用 super()。传递 props 给 super() 的原因则是便于(在子类中)能在constructor 访问 this.props。

应该在 React 组件的何处发起 Ajax 请求

在 React 组件中,应该在 componentDidMount 中发起网络请求。这个方法会在组件第一次“挂载”(被添加到DOM)时执行,在组件的生命周期中仅会执行一次。更重要的是,你不能保证在组件挂载之前 Ajax 请求已经成,如果是这样,也就意味着你将尝试在一个未挂载的组件上调用 setState,这将不起作用。componentDidMount 中发起网络请求将保证这有一个组件可以更新了。

描述事件在 React 中的处理方式。

为了解决跨浏览器兼容性问题,您的 React 中的事件处理程序将传递SyntheticEvent 的实例,它是 React 的浏览器本机事件的跨浏览器包装器。这些 SyntheticEvent 与您习惯的原生事件具有相同的接口,除了它们在所有浏览器中都兼容。有趣的是,React 实际上并没有将事件附加到子节点本身。React 将使用单个事件监听器监听顶层的所有事件。这对于性能是有好处的,这也意味着在更新 DOM 时,React 不需要担心跟踪事件监听器。

了解 redux 么,说一下 redux 把

• redux 是一个应用数据流框架,主要是解决了组件间状态共享的问题,原理是集中式管理,主要有三个核心方法,action,store,reducer,工作流程是view 调用 store 的 dispatch 接收 action 传入 store,reducer 进行 state 操作,view 通过 store 提供的 getState 获取最新的数据,flux 也是用来进行数据操作的,有四个组成部分 action,dispatch,view,store,工作流程是view 发出一个 action,派发器接收 action,让 store 进行数据更新,更新完成以后 store 发出 change,view 接受 change 更新视图。Redux 和 Flux 很像。主要区别在于 Flux 有多个可以改变应用状态的 store,在 Flux 中dispatcher 被用来传递数据到注册的回调事件,但是在 redux 中只能定义一个可更新状态的 store,redux 把 store 和 Dispatcher 合并,结构更加简单清晰

• 新增 state,对状态的管理更加明确,通过 redux,流程更加规范了,减少手动编码量,提高了编码效率,同时缺点时当数据更新时有时候组件不需要,但是也要重新绘制,有些影响效率。一般情况下,我们在构建多交互,多数据流的复杂项目应用时才会使用它们

redux 有什么缺点

• 一个组件所需要的数据,必须由父组件传过来,而不能像 flux 中直接从store 取。
• 当一个组件相关数据更新时,即使父组件不需要用到这个组件,父组件还是会重新 render,可能会有效率影响,或者需要写复杂的shouldComponentUpdate 进行判断。

1.react中组件定义的方式

  1. 使用function定义组件(主流,官方推荐,无状态组件结合hooks实现快速开发)
  2. 使用class定义组件(还有人在用)
  3. React.createClass定义组件(极少数人再用)

注意:class定义的组件需要有一个render方法,返回一个HTML标签,表示当前组件展示的HTML内部部分,此方法在数据或者睡属性改变之后都会重复执行,react是单向数据流

​ class定义组件时,state可以为组件定义局部转台

​ state的数据改变以后需要使用setState方法实现

​ 当数据改变以后render方法会重新执行

区别:

function定义组件没有this指向问题

class定义的组件有自己的据状态和生命周期函数

function定义的组件又叫做无状态组件,但是16.8之后可以使用hooks模拟组件的局部状态和生命周期

目前官方建议使用function定义组件,写法简单、容易理解

我目前一直在使用function定义组件

2.react中要分别引入babel,react,react-dom,一定要注意顺序,因为js引入会有依赖顺序,要按序引入。

3.react中数据改变是异步的,如果想获取最新数据,可以给初始化数据为1

4.react传参

父组件向子组件传参,用props属性

子组件向父组件传参,使用方法调用

5.react钩子函数

componentWillMount

componentDidMount

render

shouldComponentUpdate

componentWillUpdate

componentDidUpdate

componentWillUnmount

6.react代码优化

7.react路由

路由基础使用

//HashRouter哈希路由
//BrowserRouter浏览器历史记录路由
//as 作用重新命名
import { HashRouter as Router, Route, Link, Switch } from 'react-router-dom'
// Router表示最顶层的路由组件对象,一个项目只能有一个
// Route表示每一个地址对应显示的组件内容,可以有多个
//	如果要让地址绝对匹配,需要添加属性exact
// Link生成a标签
// Switch表示路由内容Route只匹配一个就不往后走了
//eg:

    【首页】
    【电影】//可以拼接
    
} /> /Route> //模糊匹配,现有路由匹配不上时选择这一个
路由获取参数的方法:
new URLSearchParams 是原生js内置的方法,用来获取url中传递的参数
 const  zhuan =new URLSearchParams(props.location.search)
 console.log(zhuan.get('id'))
 使用路由后,会自动在props中自动的加上以下属性
//location,表示当前路由地址
//history, 表示历史记录信息,里面有跳转方法 push pop go 
//metch 可以使用的一些匹配方法
import { useLocation } from "react-router-dom";
// useLocation 可以获取当前props传递的location数据

import { useParams } from "react-router-dom";
// useParams 可以获取当前props传递的id数据


路由传参的方法:
路由传参分为三种
query,参数拼接在url上面,传入的是拼接的字符串,刷新页面时参数还在
params,参数不在url上,传入的是对象,传参刷新后会消失
state,参数不在url上,传入的是对象,传参刷新后会消失
补充:解决params和state刷新后消失,在path后拼接占位符<Route path='/detail/:id' component={Detail} />,在pathname后面拼接id,search:"?id="+item.albumId,(传值个数与占位符数目相同,占位符是传值的属性名)

1.通过?直接传参
{/* {v.name} */}
2.通过query传参
qs 可以用来解析和格式化url中传递的参数
import {stringify,parse}from 'qs'
// const p = { a: 123, b: true, c: "我是小明" };
// console.log(stringify(p));
// console.log(parse(p));

 const temQuery={id:v._id ,b:789 }
 <Link to={"/detail?" +stringify(temQuery) }>{v.name}</Link>
3.通过params传参
 但是一刷新就没有了
4.通过state传参
但是一刷新就没了
 <Link 
      to={{
             pathname:"/detail",//表示路由对应的组件的path
             params/state:{id:v._id},
         }}                  
 >{v.name}
 </Link>

5.解决params传参刷新数据丢失问题
通过占位符可以解决
<Route path='/detail/:id' component={Detail}></Route>
<Link 
     to={{
         pathname:"/detail/"+v._id,
         search:"?id=" + v._id,
         params:{id:v._id},
     }}

      >{v.name}
 </Link>
6.withRouter 是一个高阶组件,可以把路由属性传递到组件的属性中进行使用
高阶组件就是把一个组件当参数传递到一个function进行封装,为其添加新的属性
高阶组件最常见的两个例子:withRouter和connect
高阶组件就是高阶函数,常见的高阶函数有map和foreach
import {withRouter}from 'react-router-dom'
export default withRouter(Gao)
通俗的说:将一个没有被Route路由包裹的组件包裹进Route里面,然后react-router的三个对象history, location, match就会被放进这个组件的props属性中. 就能实现编程式导航跳转
路由中定义组件的方法
1.
<Route path='/detail/:id' component={Detail}></Route>
2.
<Route path='/detail'>
    <Detail>
</Route>
3.
<Route path='/detail' render={()=><List/>}></Route>

前两中想要获取属性必须使用withRouter方法,第三种不用,第三种在用私有路由的时候作用大。

私有路由
先自己定义一个组件,判断localstorage中是否有token,有token的话,就展现当前页面,没有token,就跳转到登录页
import React from 'react'
import {Redirect,Route} from 'react-router-dom'
//Redirect重定向
function ProtectedRoute(props) {
    console.log(props)
    console.group("私有路由")
    console.log(props)
    console.groupEnd()
    //写法一
    /* return (
        localStorage.getItem('token')?}/>:
    ) */
    
    //写法二(官方写法)
    const {children,...rest} = props//解构赋值,...rest为剩下的项,当成属性直接放在中
    return localStorage.getItem('token')?children:} />
}
export default ProtectedRoute

使用私有路由
import ProtectedRoute from './components/ProtectedRoute'
【我的】

{/* 写法一 */}
{/*  */}
{/* 写法二(官方写法) */}

    


路由跳转
props.history.push("/user/info");
//history可以实现编程式跳转
//push直接跳转,相当于向路由栈中插入一个新纪录
//go(-1)回退
//goback回退

redux

是一个全局状态管理插件,作用是对数据进行管理,热镀锌是针对数据进行操作的,可以结合任何一个js库进行使用。react是一个针对视图层的library,所以一般在做开发的时候都会把react和redux进行结合使用。

redux是单向数据流的,数据是单向流动的,state用来存储数据,所有的数据改变都在reducer中进行,redux中还有一个action,它用来组织数据

单向数据流的概念:数据是单向流动的,view通过dispatch派发一个action改变数据,数据改变之后页面重新渲染。

三部分:state,reducer,action

  • state用来存储数据
  • reducer 用来处理和改变数据,每一个reducer都是一个function,返回一个对象作为数据内容,所有的reducer每一次都会返回一个新的对象作为数据,目的是不进行原始数据的比较,这样子性能更高。
  • action用来组织数据,传递reducer来进行数据的改变操作,每一个action需要有一个属性叫type,表示数据以什么方式改变,action必须是一个plain object
  • 如果要做异步action,需要借助中间件redux-thunk,这个中间件的源码很少,只有几十行,做欧阳是判断当前的action是什么,如果是对象就直接派发,如果是function,那么function执行完成之后派发,同时把dispatch当参数传递给方法。

每一个reducer接收两个参数

参数一 表示初始状态

参数二 表示action 每一个action必须有一个type属性

要通过dispatch派发一个action改变数据,action必须是一个对象。通过switch接收,参数为action.type

store.dispatch({
  type:"ADD_COUNT",
  payload:{
    step:2,
  },
});

 switch(action.type){
    case "ADD_COUNT":
      return { ...state, age:state.age + action.payload.step};
         //type是action固定的属性
         //payload指的是载荷,是一个编程习惯,一般传的数据一般都放在payload里面
    default:
      return state;
    }
}

Provider可以把redux数据和react项目做关联

connect 作用是把redux中的数据和react组件的props属性做关联

组件的props属性中会多出来一个dispatch方法和redux中的数据内容

export default connect((abc)=>abc)(App); 

redux 跨组件传参,可以用全局状态共享

通过dispatch派发一个action改变数据,组件中props来接收,connect是关联的桥梁,把属性映射到组件里面

当做异步action时,必须使用中间件实现。

combineReducers可以把多个reducer合并成一个

applyMiddleware允许使用一个中间件,compose是引入一个第三方中间件

 引入
 import {createStore,combineReducers,compose,applyMiddleware} from 'redux';
 compose(
    applyMiddleware(...[thunk,x,xxx],//加入我们要使用的中间件,多个的话中间用逗号隔开
      window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
      ),
    ),

thunk的作用,当使用了redux-thunk之后,action可以是一个function

import thunk from 'redux-thunk'//作用是可以在redux中使用异步action

umi

可以为我们自动配置路由

嵌套路由— _layout.tsx tsx是一个ts 文件 ts语法跟js语法一样,如果报错的话,就写成props:any

母版页,是一个嵌套路由

改变路由,histroy改成hash的话,就加一个文件即可

umi的打包:在package.json中scripts下,手动添加 “build”:‘umi build’,cmd端输入npm run dev即可

dva是用来做数据处理的,所有的数据处理都在dva中进行管理的

你可能感兴趣的:(reactjs,html,css,jquery,javascript)