关于前端:美团前端经典react面试题整理

47次阅读

共计 6702 个字符,预计需要花费 17 分钟才能阅读完成。

react 强制刷新

component.forceUpdate() 一个不罕用的生命周期办法, 它的作用就是强制刷新

官网解释如下

默认状况下,当组件的 state 或 props 发生变化时,组件将从新渲染。如果 render() 办法依赖于其余数据,则能够调用 forceUpdate() 强制让组件从新渲染。

调用 forceUpdate() 将以致组件调用 render() 办法,此操作会跳过该组件的 shouldComponentUpdate()。但其子组件会触发失常的生命周期办法,包含 shouldComponentUpdate() 办法。如果标记发生变化,React 仍将只更新 DOM。

通常你应该防止应用 forceUpdate(),尽量在 render() 中应用 this.props 和 this.state。

shouldComponentUpdate 在初始化 和 forceUpdate 不会执行

React 父组件如何调用子组件中的办法?

  1. 如果是在办法组件中调用子组件(>= react@16.8),能够应用 useRef 和 useImperativeHandle:
const {forwardRef, useRef, useImperativeHandle} = React;

const Child = forwardRef((props, ref) => {useImperativeHandle(ref, () => ({getAlert() {alert("getAlert from Child");
    }
  }));
  return <h1>Hi</h1>;
});

const Parent = () => {const childRef = useRef();
  return (
    <div>
      <Child ref={childRef} />
      <button onClick={() => childRef.current.getAlert()}>Click</button>
    </div>
  );
};
  1. 如果是在类组件中调用子组件(>= react@16.4),能够应用 createRef:
const {Component} = React;

class Parent extends Component {constructor(props) {super(props);
    this.child = React.createRef();}

  onClick = () => {this.child.current.getAlert();
  };

  render() {
    return (
      <div>
        <Child ref={this.child} />
        <button onClick={this.onClick}>Click</button>
      </div>
    );
  }
}

class Child extends Component {getAlert() {alert('getAlert from Child');
  }

  render() {return <h1>Hello</h1>;}
}

React 中 Diff 算法的原理是什么?

原理如下。
(1)节点之间的比拟。
节点包含两种类型:一种是 React 组件,另一种是 HTML 的 DOM。
如果节点类型不同,按以下形式比拟。
如果 HTML DOM 不同,间接应用新的替换旧的。如果组件类型不同,也间接应用新的替换旧的。
如果 HTML DOM 类型雷同,按以下形式比拟。
在 React 里款式并不是一个纯正的字符串,而是一个对象,这样在款式产生扭转时,只须要扭转替换变动当前的款式。批改完以后节点之后,递归解决该节点的子节点。
如果组件类型雷同,按以下形式比拟。
如果组件类型雷同,应用 React 机制解决。个别应用新的 props 替换旧的 props,并在之后调用组件的 componentWillReceiveProps 办法,之前组件的 render 办法会被调用。
节点的比拟机制开始递归作用于它的子节点。
(2)两个列表之间的比拟。
一个节点列表中的一个节点产生扭转,React 无奈很妤地解决这个问题。循环新旧两个列表,并找出不同,这是 React 惟一的解决办法。
然而,有一个方法能够把这个算法的复杂度升高。那就是在生成一个节点列表时给每个节点上增加一个 key。这个 key 只须要在这一个节点列表中惟一,不须要全局惟一。
(3)取舍
须要留神的是,下面的启发式算法基于两点假如。
类型相近的节点总是生成同样的树,而类型不同的节点也总是生成不同的树
能够为屡次 render 都体现稳固的节点设置 key。
下面的节点之间的比拟算法基本上就是基于这两个假如而实现的。要进步 React 利用的效率,须要依照这两点假如来开发。

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

该函数会在 setState 函数调用实现并且组件开始重渲染的时候被调用,咱们能够用该函数来监听渲染是否实现:

this.setState({ username: 'tylermcginnis33'},
  () => console.log('setState has finished and the component has re-rendered.')
)
this.setState((prevState, props) => {
  return {streak: prevState.streak + props.count}
})

redux 有什么毛病

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

redux 中间件

中间件提供第三方插件的模式,自定义拦挡 action -> reducer 的过程。变为 action -> middlewares -> reducer。这种机制能够让咱们扭转数据流,实现如异步actionaction 过滤,日志输入,异样报告等性能

  • redux-logger:提供日志输入
  • redux-thunk:解决异步操作
  • redux-promise:解决异步操作,actionCreator的返回值是promise

参考 前端进阶面试题具体解答

组件更新有几种办法

  • this.setState() 批改状态的时候 会更新组件
  • this.forceUpdate() 强制更新
  • 组件件 render 之后,子组件应用到父组件中状态,导致子组件的 props 属性产生扭转的时候 也会触发子组件的更新

什么是 React 的 refs?为什么它们很重要

refs 容许你间接拜访 DOM 元素或组件实例。为了应用它们,能够向组件增加个 ref 属性。
如果该属性的值是一个回调函数,它将承受底层的 DOM 元素或组件的已挂载实例作为其第一个参数。能够在组件中存储它。

export class App extends Component {showResult() {console.log(this.input.value);
  }
  render() {
    return (
      <div>
        <input type="text" ref={(input) => (this.input = input)} />
        <button onClick={this.showResult.bind(this)}> 展现后果 </button>
      </div>
    );
  }
}

如果该属性值是一个字符串,React 将会在组件实例化对象的 refs 属性中,存储一个同名属性,该属性是对这个 DOM 元素的援用。能够通过原生的 DOM API 操作它。

export class App extends Component {showResult() {console.log(this.refs.username.value);
  }
  render() {
    return (
      <div>
        <input type="text" ref="username" />
        <button onClick={this.showResu1t.bind(this)}> 展现后果 </button>
      </div>
    );
  }
}

React 中 refs 的作用是什么

  • RefsReact 提供给咱们的平安拜访 DOM元素或者某个组件实例的句柄
  • 能够为元素增加 ref 属性而后在回调函数中承受该元素在 DOM 树中的句柄,该值会作为回调函数的第一个参数返回

hooks 为什么不能放在条件判断里

以 setState 为例,在 react 外部,每个组件 (Fiber) 的 hooks 都是以链表的模式存在 memoizeState 属性中

update 阶段,每次调用 setState,链表就会执行 next 向后挪动一步。如果将 setState 写在条件判断中,假如条件判断不成立,没有执行外面的 setState 办法,会导致接下来所有的 setState 的取值呈现偏移,从而导致异样产生。

useEffect(fn, []) 和 componentDidMount 有什么差别

useEffect 会捕捉 props 和 state。所以即使在回调函数里,你拿到的还是初始的 props 和 state。如果想得到“最新”的值,能够应用 ref。

生命周期调用办法的程序是什么?

React 生命周期分为三大周期,11 个阶段,生命周期办法调用程序别离如下。
(1)在创立期的五大阶段,调用办法的程序如下。

  • getDetaultProps:定义默认属性数据。
  • getInitialState:初始化默认状态数据。
  • component WillMount:组件行将被构建。
  • render:渲染组件。
  • componentDidMount:组件构建实现

(2)在存在期的五大阶段,调用办法的程序如下。

  • componentWillReceiveProps:组件行将接管新的属性数据。
  • shouldComponentUpdate:判断组件是否应该更新。
  • componnent WillUpdate:组件行将更新。
  • render:渲染组件。
  • componentDidUpdate:组件更新实现。

(3)在销毁期的一个阶段,调用办法 componentWillUnmount,示意组件行将被销毀。

react 性能优化计划

  • 重写 shouldComponentUpdate 来防止不必要的 dom 操作
  • 应用 production 版本的react.js
  • 应用 key 来帮忙 React 辨认列表中所有子组件的最小变动

这三个点 (…) 在 React 干嘛用的?

... 在 React(应用 JSX)代码中做什么?它叫什么?

<Modal {...this.props} title='Modal heading' animation={false}/>

这个叫扩大操作符号或者开展操作符,例如,如果 this.props 蕴含 a:1b:2,则

<Modal {...this.props} title='Modal heading' animation={false}>

等价于上面内容:

<Modal a={this.props.a} b={this.props.b} title='Modal heading' animation={false}>

扩大符号不仅实用于该用例,而且对于创立具备现有对象的大多数(或全副)属性的新对象十分不便,在更新state 咱们就常常这么做:

this.setState((prevState) => {return { foo: { ...prevState.foo, a: "updated"} };
});

diff 算法?

  • 把树形构造依照层级合成,只比拟同级元素。
  • 给列表构造的每个单元增加惟一的 key 属性,不便比拟。
  • React 只会匹配雷同 classcomponent(这外面的 class 指的是组件的名字)
  • 合并操作,调用 componentsetState 办法的时候, React 将其标记为 – dirty. 到每一个事件循环完结, React 查看所有标记 dirtycomponent从新绘制.
  • 抉择性子树渲染。开发人员能够重写 shouldComponentUpdate 进步 diff 的性能

在结构函数调用 super 并将 props 作为参数传入的作用是啥?

在调用 super() 办法之前,子类构造函数无奈应用 this 援用,ES6 子类也是如此。将 props 参数传递给 super() 调用的次要起因是在子构造函数中可能通过 this.props 来获取传入的 props
传递 props

class MyComponent extends React.Component {constructor(props) {super(props);
    console.log(this.props); // {name: 'sudheer',age: 30}
  }
}

没传递 props

class MyComponent extends React.Component {constructor(props) {super();
    console.log(this.props); // undefined
    // 然而 Props 参数依然可用
    console.log(props); // Prints {name: 'sudheer',age: 30}
  }
  render() {
    // 构造函数内部不受影响
    console.log(this.props); // {name: 'sudheer',age: 30}
  }
}

下面示例揭示了一点。props 的行为只有在构造函数中是不同的,在构造函数之外也是一样的。

这段代码有什么问题?

class App extends Component {constructor(props) {super(props);
    this.state = {
      username: "有课前端网",
      msg: " ",
    };
  }
  render() {return <div> {this.state.msg}</div>;
  }
  componentDidMount() {this.setState((oldState, props) => {
      return {msg: oldState.username + "-" + props.intro,};
    });
  }
}

render (< App intro=” 前端技术业余学习平台 ”></App>,ickt)
在页面中失常输入“有课前端网 - 前端技术业余学习平台”。然而这种写法很少应用,并不是罕用的写法。React 容许对 setState 办法传递一个函数,它接管到先前的状态和属性数据并返回一个须要批改的状态对象,正如咱们在下面所做的那样。它岂但没有问题,而且如果依据以前的状态(state)以及属性来批改以后状态,举荐应用这种写法。

React- Router 有几种模式?

有以下几种模式。
HashRouter,通过散列实现,路由要带 #。
BrowerRouter,利用 HTML5 中 history API 实现,须要服务器端反对,兼容性不是很好。

如何应用 4.0 版本的 React Router?

React Router 4.0 版本中对 hashHistory 做了迁徙,执行包装置命令 npm install react-router-dom 后,依照如下代码进行应用即可。

import {HashRouter, Route, Redirect, Switch} from "react-router-dom";
class App extends Component {render() {
    return (
      <div>
        <Switch>
          <Route path="/list" componen t={List}></Route>
          <Route path="/detail/:id" component={Detail}>
            {" "}
          </Route>
          <Redirect from="/" to="/list">
            {" "}
          </Redirect>
        </Switch>
      </div>
    );
  }
}
const routes = (
  <HashRouter>
    <App> </App>
  </HashRouter>
);
render(routes, ickt);

React 中的 useState() 是什么?

上面阐明 useState(0) 的用处:

const [count, setCounter] = useState(0);
const [moreStuff, setMoreStuff] = useState();

const setCount = () => {setCounter(count + 1);
  setMoreStuff();};

useState 是一个内置的 React Hook。useState(0) 返回一个元组,其中第一个参数 count 是计数器的以后状态,setCounter 提供更新计数器状态的办法。
咱们能够在任何中央应用 setCounter 办法更新计数状态 - 在这种状况下,咱们在 setCount 函数外部应用它能够做更多的事件,应用 Hooks,可能使咱们的代码放弃更多功能,还能够防止过多应用基于类的组件。

正文完
 0