写点什么

京东前端二面高频 react 面试题

作者:Geek_07a724
  • 2022 年 9 月 14 日
    浙江
  • 本文字数:6747 字

    阅读完需:约 22 分钟

ref 是一个函数又有什么好处?

  • 方便 react 销毁组件、重新渲染的时候去清空 refs 的东西,防止内存泄露

解释 React 中 render() 的目的。

每个 React 组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form><group><div> 等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。

什么是 JSX

jsx 是 JavaScriptXML 的简写,是 react 使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的模板语法,这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能 jsx 的语法规则


  • 定义虚拟 DOM 的时候 不需要写引号

  • 标签中要混入 js 表达式的时候需要用 {}

  • 在 jsx 中写标签的类名的时候 用 className 代替 class

  • 内联样式的时候 ,需要 style={{key:value}}

  • 标签必须要闭合

  • 标签首字母的约定

  • 若为小写字母,则将 jsx 转换为 html 中同名元素,若 html 中无该标签明对应的同名元素 则报错

  • 若为大写字母,react 就去渲染对应的组件,若没有定义组件 则报错

  • 当根据数据遍历生成的标签,一定要给标签设置单独的 key 否则会报错

React 中 keys 的作用是什么?

KeysReact 用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识


  • 在开发过程中,我们需要保证某个元素的 key 在其同级元素中具有唯一性。在 React Diff 算法中React 会借助元素的 Key 值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助 Key 值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中 Key 的重要性

react 实现一个全局的 dialog

import React, { Component } from 'react';import { is, fromJS } from 'immutable';import ReactDOM from 'react-dom';import ReactCSSTransitionGroup from 'react-addons-css-transition-group';import './dialog.css';let defaultState = {  alertStatus:false,  alertTip:"提示",  closeDialog:function(){},  childs:''}class Dialog extends Component{  state = {    ...defaultState  };  // css动画组件设置为目标组件  FirstChild = props => {    const childrenArray = React.Children.toArray(props.children);    return childrenArray[0] || null;  }  //打开弹窗  open =(options)=>{    options = options || {};    options.alertStatus = true;    var props = options.props || {};    var childs = this.renderChildren(props,options.childrens) || '';    console.log(childs);    this.setState({      ...defaultState,      ...options,      childs    })  }  //关闭弹窗  close(){    this.state.closeDialog();    this.setState({      ...defaultState    })  }  renderChildren(props,childrens) {    //遍历所有子组件    var childs = [];    childrens = childrens || [];    var ps = {        ...props,  //给子组件绑定props        _close:this.close  //给子组件也绑定一个关闭弹窗的事件           };    childrens.forEach((currentItem,index) => {        childs.push(React.createElement(            currentItem,            {                ...ps,                key:index            }        ));    })    return childs;  }  shouldComponentUpdate(nextProps, nextState){    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))  }     render(){    return (      <ReactCSSTransitionGroup        component={this.FirstChild}        transitionName='hide'        transitionEnterTimeout={300}        transitionLeaveTimeout={300}>        <div className="dialog-con" style={this.state.alertStatus? {display:'block'}:{display:'none'}}>            {this.state.childs}        </div>      </ReactCSSTransitionGroup>    );  }}let div = document.createElement('div');let props = {   };document.body.appendChild(div);let Box = ReactD
复制代码


子类:


//子类jsximport React, { Component } from 'react';class Child extends Component {    constructor(props){        super(props);        this.state = {date: new Date()};  }  showValue=()=>{    this.props.showValue && this.props.showValue()  }  render() {    return (      <div className="Child">        <div className="content">           Child           <button onClick={this.showValue}>调用父的方法</button>        </div>      </div>    );  }}export default Child;
复制代码


css:


.dialog-con{    position: fixed;    top: 0;    left: 0;    width: 100%;    height: 100%;    background: rgba(0, 0, 0, 0.3);}
复制代码

概述一下 React 中的事件处理逻辑。

为了解决跨浏览器兼容性问题, React 会将浏览器原生事件( Browser Native Event)封装为合成事件( Synthetic Event)并传入设置的事件处理程序中。这里的合成事件提供了与原生事件相同的接口,不过它们屏蔽了底层浏览器的细节差异,保证了行为的一致性。另外, React 并没有直接将事件附着到子元素上,而是以单一事件监听器的方式将所有的事件发送到顶层进行处理(基于事件委托原理)。这样 React 在更新 DOM 时就不需要考虑如何处理附着在 DOM 上的事件监听器,最终达到优化性能的目的。

传入 setstate 函数的第二个参数的作用是什么?

第二个参数是一个函数,该函数会在 setState 函数调用完成并且组件开始重渲染时调用,可以用该函数来监听渲染是否完成。


this.setstate(  {    username: "有课前端网",  },  () => console.log("re-rendered success. "));
复制代码

refs 的作用是什么,你在什么样的业务场景下使用 refs

  • 操作 DOM,为什么操作 DOM?

  • 场景

  • 图片渲染好后,操作图片宽高。比如做个放大镜功能

(组件的)状态(state)和属性(props)之间有何不同

State 是一种数据结构,用于组件挂载时所需数据的默认值。State 可能会随着时间的推移而发生突变,但多数时候是作为用户事件行为的结果。


Props(properties 的简写)则是组件的配置。props 由父组件传递给子组件,并且就子组件而言,props 是不可变的(immutable)。组件不能改变自身的 props,但是可以把其子组件的 props 放在一起(统一管理)。Props 也不仅仅是数据--回调函数也可以通过 props 传递。

什么是上下文 Context

Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。


  • 用法:在父组件上定义 getChildContext 方法,返回一个对象,然后它的子组件就可以通过 this.context 属性来获取


import React,{Component} from 'react';import ReactDOM from 'react-dom';import PropTypes from 'prop-types';class Header extends Component{    render() {        return (            <div>                <Title/>            </div>        )    }}class Title extends Component{    static contextTypes={        color:PropTypes.string    }    render() {        return (            <div style={{color:this.context.color}}>                Title            </div>        )    }}class Main extends Component{    render() {        return (            <div>                <Content>                </Content>            </div>        )    }}class Content extends Component{    static contextTypes={        color: PropTypes.string,        changeColor:PropTypes.func    }    render() {        return (            <div style={{color:this.context.color}}>                Content                <button onClick={()=>this.context.changeColor('green')}>绿色</button>                <button onClick={()=>this.context.changeColor('orange')}>橙色</button>            </div>        )    }}class Page extends Component{    constructor() {        super();        this.state={color:'red'};    }    static childContextTypes={        color: PropTypes.string,        changeColor:PropTypes.func    }    getChildContext() {        return {            color: this.state.color,            changeColor:(color)=>{                this.setState({color})            }        }    }    render() {        return (            <div>                <Header/>                <Main/>            </div>        )    }}ReactDOM.render(<Page/>,document.querySelector('#root'));
复制代码

react 有什么优点

  • 提高应用性能

  • 可以方便的在客户端和服务端使用

  • 使用 jsx 模板进行数据渲染,可读性好

react 中 key 的作用

简单的说:key 是虚拟 DOM 中的一种标识,在更新显示是 key 起到了极其重要的作用


复杂的说:当状态中的数据发生改变的时候,react 会根据【新数据】生成【新的虚拟 DOM】,随后 react 进行【新虚拟 DOM】 和 【旧的虚拟 DOM】的 diff 比较,而在这个比较过程中 key 就是起到是关键中用

与 ES5 相比,React 的 ES6 语法有何不同

以下语法是 ES5 与 ES6 中的区别:


  1. require 与 import


// ES5var React = require('react');
// ES6import React from 'react';
复制代码


  1. export 与 exports


// ES5module.exports = Component;
// ES6export default Component;
复制代码


  1. component 和 function


// ES5var MyComponent = React.createClass({    render: function() {        return            <h3>Hello Edureka!</h3>;    }});
// ES6class MyComponent extends React.Component { render() { return <h3>Hello Edureka!</h3>; }}
复制代码


  1. props


// ES5var App = React.createClass({    propTypes: { name: React.PropTypes.string },    render: function() {        return            <h3>Hello, {this.props.name}!</h3>;    }});
// ES6class App extends React.Component { render() { return <h3>Hello, {this.props.name}!</h3>; }}
复制代码


  1. state


// ES5var App = React.createClass({    getInitialState: function() {        return { name: 'world' };    },    render: function() {        return            <h3>Hello, {this.state.name}!</h3>;    }});
// ES6class App extends React.Component { constructor() { super(); this.state = { name: 'world' }; } render() { return <h3>Hello, {this.state.name}!</h3>; }}
复制代码

组件之间传值

  • 父组件给子组件传值

  • 在父组件中用标签属性的=形式传值

  • 在子组件中使用 props 来获取值

  • 子组件给父组件传值

  • 在组件中传递一个函数

  • 在子组件中用 props 来获取传递的函数,然后执行该函数

  • 在执行函数的时候把需要传递的值当成函数的实参进行传递

  • 兄弟组件之间传值

  • 利用父组件

  • 先把数据通过 【子组件】===》【父组件】

  • 然后在数据通过 【父组件】===〉【子组件】

  • 消息订阅

  • 使用 PubSubJs 插件

React Portal 有哪些使用场景

  • 在以前, react 中所有的组件都会位于 #app 下,而使用 Portals 提供了一种脱离 #app 的组件

  • 因此 Portals 适合脱离文档流(out of flow) 的组件,特别是 position: absolute 与 position: fixed 的组件。比如模态框,通知,警告,goTop 等。


以下是官方一个模态框的示例,可以在以下地址中测试效果


<html>  <body>    <div id="app"></div>    <div id="modal"></div>    <div id="gotop"></div>    <div id="alert"></div>  </body></html>
复制代码


const modalRoot = document.getElementById('modal');
class Modal extends React.Component { constructor(props) { super(props); this.el = document.createElement('div'); }
componentDidMount() { modalRoot.appendChild(this.el); }
componentWillUnmount() { modalRoot.removeChild(this.el); }
render() { return ReactDOM.createPortal( this.props.children, this.el, ); }}
复制代码


React Hooks 当中的 useEffect 是如何区分生命周期钩子的


useEffect 可以看成是componentDidMountcomponentDidUpdatecomponentWillUnmount三者的结合。useEffect(callback, [source])接收两个参数,调用方式如下


useEffect(() => {   console.log('mounted');
return () => { console.log('willUnmount'); } }, [source]);
复制代码


生命周期函数的调用主要是通过第二个参数[source]来进行控制,有如下几种情况:


  • [source]参数不传时,则每次都会优先调用上次保存的函数中返回的那个函数,然后再调用外部那个函数;

  • [source]参数传[]时,则外部的函数只会在初始化时调用一次,返回的那个函数也只会最终在组件卸载时调用一次;

  • [source]参数有值时,则只会监听到数组中的值发生变化后才优先调用返回的那个函数,再调用外部的函数。

React-Router 如何获取 URL 的参数和历史对象?

(1)获取 URL 的参数


  • get 传值


路由配置还是普通的配置,如:'admin',传参方式如:'admin?id='1111''。通过this.props.location.search获取 url 获取到一个字符串'?id='1111' 可以用 url,qs,querystring,浏览器提供的 api URLSearchParams 对象或者自己封装的方法去解析出 id 的值。


  • 动态路由传值


路由需要配置成动态路由:如path='/admin/:id',传参方式,如'admin/111'。通过this.props.match.params.id 取得 url 中的动态路由 id 部分的值,除此之外还可以通过useParams(Hooks)来获取


  • 通过 query 或 state 传值


传参方式如:在 Link 组件的 to 属性中可以传递对象{pathname:'/admin',query:'111',state:'111'};。通过this.props.location.statethis.props.location.query来获取即可,传递的参数可以是对象、数组等,但是存在缺点就是只要刷新页面,参数就会丢失。


(2)获取历史对象


  • 如果 React >= 16.8 时可以使用 React Router 中提供的 Hooks


import { useHistory } from "react-router-dom";let history = useHistory();
复制代码


2.使用 this.props.history 获取历史对象


let history = this.props.history;
复制代码

展示组件(Presentational component)和容器组件(Container component)之间有何不同

展示组件关心组件看起来是什么。展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。


容器组件则更关心组件是如何运作的。容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions,并将其作为回调提供给展示组件。容器组件经常是有状态的,因为它们是(其它组件的)数据源。

为什么使用 jsx 的组件中没有看到使用 react 却需要引入 react?

本质上来说 JSX 是React.createElement(component, props, ...children)方法的语法糖。在 React 17 之前,如果使用了 JSX,其实就是在使用 React, babel 会把组件转换为 CreateElement 形式。在 React 17 之后,就不再需要引入,因为 babel 已经可以帮我们自动引入 react。

createElement 过程

React.createElement(): 根据指定的第一个参数创建一个 React 元素


React.createElement(  type,  [props],  [...children])
复制代码


  • 第一个参数是必填,传入的是似 HTML 标签名称,eg: ul, li

  • 第二个参数是选填,表示的是属性,eg: className

  • 第三个参数是选填, 子节点,eg: 要显示的文本内容


//写法一:
var child1 = React.createElement('li', null, 'one'); var child2 = React.createElement('li', null, 'two'); var content = React.createElement('ul', { className: 'teststyle' }, child1, child2); // 第三个参数可以分开也可以写成一个数组 ReactDOM.render( content, document.getElementById('example') );
//写法二:
var child1 = React.createElement('li', null, 'one'); var child2 = React.createElement('li', null, 'two'); var content = React.createElement('ul', { className: 'teststyle' }, [child1, child2]); ReactDOM.render( content, document.getElementById('example') );
复制代码

componentWillReceiveProps 调用时机

  • 已经被废弃掉

  • 当 props 改变的时候才调用,子组件第二次接收到 props 的时候

用户头像

Geek_07a724

关注

还未添加个人签名 2022.09.14 加入

还未添加个人简介

评论

发布
暂无评论
京东前端二面高频react面试题_前端_Geek_07a724_InfoQ写作社区