1. Разница между элементами и компонентами в React
В то время я только учился реагировать, и я не знал, что интервьюер сказал об элементах, теперь я знаю, что это виртуальный дом. . .
Реагировать элемент
Это самая маленькая базовая единица в React, и мы можем легко создать элемент React, используя синтаксис JSX:
const element = <div className="element">I'm element</div>
Элементы React не являются настоящими элементами DOM, они являются просто объектами js, поэтому нет возможности напрямую вызывать нативные API DOM. Приведенный выше переведенный объект JSX выглядит следующим образом:
{
_context: Object,
_owner: null,
key: null,
props: {
className: 'element',
children: 'I'm element'
},
ref: null,
type: "div"
}
В дополнение к использованию синтаксиса JSX мы также можем использовать React.createElement() и React.cloneElement() для создания элементов React.
Реагировать компоненты
Есть три способа создания компонентов в React. React.createClass(), классы ES6 и функции без сохранения состояния.
1. Реагировать.создатькласс()
var Greeting = React.createClass({
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
});
2. Класс ES6
class Greeting extends React.Component{
render: function() {
return <h1>Hello, {this.props.name}</h1>;
}
};
3. Функции без состояния
Функция без состояния — это компонент без состояния, созданный с помощью функции. Компонент без состояния передает два параметра: свойства и контекст. У него нет ни состояния, ни других методов жизненного цикла, кроме render().
function Greeting (props) {
return <h1>Hello, {props.name}</h1>;
}
4. Чистый компонент
В дополнение к предоставлению вам поверхностного сравненияshouldComponentUpdateметоды, PureComponent и Component в основном идентичны.
Разница между элементом и компонентом
Компоненты состоят из элементов. Структуры данных элементов — это обычные объекты, а структуры данных компонентов — это классы или чистые функции.
2. Скажите, пожалуйста, в чем польза Forwarding Refs
Он используется родительским компонентом для получения элемента dom дочернего компонента.Почему существует этот API?Причины следующие
// 例如有一个子组件和父组件,代码如下
子组件为:
class Child extends React.Component{
constructor(props){
super(props);
}
render(){
return <input />
}
}
// 父组件中,ref:
class Father extends React.Component{
constructor(props){
super(props);
this.myRef=React.createRef();
}
componentDidMount(){
console.log(this.myRef.current);
}
render(){
return <Child ref={this.myRef}/>
}
}
В настоящее время значением this.myRef.current родительского компонента является дочерний компонент, который является объектом.Если используется React.forwardRef, это выглядит следующим образом
// 子组件
const Child = React.forwardRef((props, ref) => (
<input ref={ref} />
));
// 父组件
class Father extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
componentDidMount() {
console.log(this.myRef.current);
}
render() {
return <Child ref={this.myRef} />
}
}
На данный момент значение this.myRef.current родительского компонента является входным элементом DOM.
3. Кратко опишите, как работает виртуальный DOM?
- При изменении данных, таких как setState, компонент будет повторно отображаться, и весь пользовательский интерфейс будет повторно отображаться в виде виртуального дома.
- Затем соберите разницу, то есть сравните разницу между новым виртуальным домом и старым виртуальным домом.
- Наконец, различия в очереди различий, такие как добавление узлов, удаление узлов, перемещение узлов, обновляются до реального DOM.
4. Знакомы ли вы с архитектурой Fiber?
Примечание. Ответ можно найти в статье Ситу Чжэнмэй.
4.1 Какие преимущества имеет архитектура Fiber по сравнению с предыдущими компонентами рекурсивного обновления?
- Причина в том, что рекурсивное обновление компонентов может привести к тому, что стек вызовов JS займет много времени.
- Поскольку браузер является однопоточной резьбой, он собирает рендеринг GUI, обработка событий, выполнение JS и т. Д., И только после того, как это сделано, можно сделать следующее. Если есть достаточно времени, браузер ответит нам. Код скомпилирован с оптимизацией (JIT) и оптимизацией горячего кода.
- Архитектура Fiber использует этот принцип для выполнения рендеринга компонентов по сегментам, чтобы у браузера было время оптимизировать код JS и исправить перекомпоновку!
4.1 Поскольку вы сказали, что Fiber рендерит компоненты сегментами, после рендеринга первого сегмента, как узнать, с какого компонента начинать рендеринг для следующего сегмента?
- У узла волокна есть три атрибута: return, child и sibling, которые соответствуют родительскому узлу, первому потомку и его правому sibling, с ними достаточно превратить дерево в связанный список для достижения глубокого оптимизационного обхода.
4.2 Как определить номер каждого обновления
- React16 необходимо преобразовать виртуальный DOM в узлы Fiber.Сначала он указывает период времени, а затем обновляет столько узлов FiberNode, сколько может преобразовать за этот период времени.
- Поэтому нам нужно разделить нашу логику обновления на два этапа: первый этап — преобразование виртуального DOM в Fiber, а Fiber — в экземпляр компонента или реальный DOM (без вставки DOM-дерева вставка DOM-дерева будет перекомпоновываться). Преобразование Fiber в последние два, очевидно, потребует времени, и необходимо рассчитать, сколько времени осталось.
- Например, вы можете записать время, когда вы начинаете обновлять видvar now = new Date - 0, если мы обновляем и пытаемся настроить это занимает 100 миллисекунд, то время окончания определения равноvar deadline = new Date + 100, Таким образом, каждый раз, когда вы обновляете часть представления, берите текущее время new Date
4.3 Как запланировать время, чтобы обеспечить бесперебойную работу
- Используйте собственный API браузера — requestIdleCallback,
- Его первый параметр — коллбэк, у колбэка есть объект параметра, у объекта есть метод timeRemaining, который эквивалентен новой дате — крайнему сроку, и это высокоточные данные, точнее миллисекунды
- Это связано с проблемами совместимости браузера, команда реагирования самостоятельно реализовала requestIdleCallback.
4.4 Какой новый жизненный цикл принесло волокно
при создании
- constructor ->
- getDerivedStateFromProps (параметры nextProps, prevState, обратите внимание, что это не указывает на экземпляр компонента) ->
- render ->
- componentDidMount
При обновлении
- getDerivedStateFromProps (это вызывается при обновлении реквизита, этот жизненный цикл не вызывается при setState, параметрах nextProps, prevState) ->
- shouldComponentUpdate(вызывать параметры nextProps, nextState когда setState)->
- render->
- getSnapsshotBeforeUpdate (заменяет componentWillUpdate)
- componentDidUpdate (параметры prevProps, prevState, моментальный снимок)
5. Что такое контролируемые и неконтролируемые компоненты
- У компонента, контролируемого состоянием, должен быть метод onChange, иначе его нельзя будет использовать.Управляемым компонентам можно присвоить значения по умолчанию (официальная рекомендация — использовать контролируемые компоненты) для реализации двусторонней привязки данных
class Input extends Component{
constructor(){
super();
this.state = {val:'100'}
}
handleChange = (e) =>{ //e是事件源
let val = e.target.value;
this.setState({val});
};
render(){
return (<div>
<input type="text" value={this.state.val} onChange={this.handleChange}/>
{this.state.val}
</div>)
}
}
- Неуправляемый означает, что я могу управлять реальным DOM через ref, не устанавливая его свойство состояния.
class Sum extends Component{
constructor(){
super();
this.state = {result:''}
}
//通过ref设置的属性 可以通过this.refs获取到对应的dom元素
handleChange = () =>{
let result = this.refs.a.value + this.b.value;
this.setState({result});
};
render(){
return (
<div onChange={this.handleChange}>
<input type="number" ref="a"/>
{/*x代表的真实的dom,把元素挂载在了当前实例上*/}
<input type="number" ref={(x)=>{
this.b = x;
}}/>
{this.state.result}
</div>
)
}
}
6. Что такое улучшение состояния?
При использовании react часто возникают ситуации, когда нескольким компонентам необходимо совместно использовать данные состояния. В этом случае нам лучше передать эту часть общего состояния их ближайшему родительскому компоненту для управления. Давайте посмотрим, как это работает.
import React from 'react'
class Child_1 extends React.Component{
constructor(props){
super(props)
}
render(){
return (
<div>
<h1>{this.props.value+2}</h1>
</div>
)
}
}
class Child_2 extends React.Component{
constructor(props){
super(props)
}
render(){
return (
<div>
<h1>{this.props.value+1}</h1>
</div>
)
}
}
class Three extends React.Component {
constructor(props){
super(props)
this.state = {
txt:"牛逼"
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(e){
this.setState({
txt:e.target.value
})
}
render(){
return (
<div>
<input type="text" value={this.state.txt} onChange={this.handleChange}/>
<p>{this.state.txt}</p>
<Child_1 value={this.state.txt}/>
<Child_2 value={this.state.txt}/>
</div>
)
}
}
export default Three
7. Что такое компонента высшего порядка
Компонент более высокого порядка — это не компонент, а функция расширения, которая может вводить метакомпонент и возвращать новый расширенный компонент.
- Реквизит Прокси На мой взгляд, прокси свойств - это извлечение публичных данных и методов в родительский компонент, а дочерний компонент отвечает только за отрисовку данных, что эквивалентно режиму шаблона в режиме разработки, так что возможность повторного использования компонента выше .
function proxyHoc(WrappedComponent) {
return class extends React.Component {
render() {
const newProps = {
count: 1
}
return <WrappedComponent {...this.props} {...newProps} />
}
}
}
- обратное наследование
const MyContainer = (WrappedComponent)=>{
return class extends WrappedComponent {
render(){
return super.render();
}
}
}
8. Что такое контекст
Контекст предоставляет способ передачи данных через дерево компонентов, избегая необходимости вручную передавать реквизиты на каждом уровне.
- Использование: определите метод 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'));
9. Что такое Portal в реакции?
Порталы предоставляют хороший способ рендеринга дочерних узлов в узлы DOM, отличные от родительского компонента.
ReactDOM.createPortal(child, container)
Первый аргумент (дочерний) — это любой отображаемый дочерний элемент React, такой как элемент, строка или фрагмент. Второй параметр (контейнер) — это элемент DOM.
10. Каковы границы ошибок реакции 16 (Границы ошибок)
Ошибки JavaScript в частях пользовательского интерфейса не должны нарушать работу всего приложения. Чтобы решить эту проблему для пользователей React, в React 16 представлена новая концепция «Границы ошибок».
import React from 'react';
import ReactDOM from 'react-dom';
class ErrorBoundary extends React.Component{
constructor(props) {
super(props);
this.state={hasError:false};
}
componentDidCatch(err,info) {
this.setState({hasError: true});
}
render() {
if (this.state.hasError) {
return <h1>Something Went Wrong</h1>
}
return this.props.children;
}
}
class Page extends React.Component{
render() {
return (
<ErrorBoundary>
<Clock/>
</ErrorBoundary>
)
}
}
class Clock extends React.Component{
render() {
return (
<div>hello{null.toString()}</div>
)
}
}
ReactDOM.render(<Page/>,document.querySelector('#root'));
11. Как использовать innerHTML в React
Добавьте свойствоhazardlySetInnerHTML, а имя свойства входящего объекта — _html.
function Component(props){
return <div dangerouslySetInnerHTML={{_html:'<span>你好</span>'}}>
</div>
}
12. Каковы этапы согласования и фиксации версии react16
- Основная работа, входящая в этап согласования, заключается в выполнении вычислений различий на текущем дереве и новом дереве для обнаружения измененных частей. Обход, сравнение и т.д. могут прерываться, а затем возвращаться через некоторое время.
- Этап фиксации заключается в применении изменений, полученных на предыдущем этапе, к реальному дереву DOM, что представляет собой серию операций DOM. Мало того, что вам нужно поддерживать более сложное состояние DOM, но если вы прерветесь, а затем продолжите, это повлияет на взаимодействие с пользователем. В распространенных сценариях приложений этот этап занимает относительно меньше времени, чем расчет различий.
13. Пожалуйста, кратко расскажите о механизме событий реакции
- Когда пользователь добавляет функцию в onClick, React не привязывает время клика к DOM.
- Вместо этого прослушивайте все поддерживаемые события в документе.Когда событие происходит и всплывает в документе, React инкапсулирует содержимое события в средний уровень SyntheticEvent (отвечает за синтез всех событий)
- Таким образом, когда событие срабатывает, унифицированная функция диспетчеризации dispatchEvent выполнит указанную функцию.
14. Почему лучше не использовать индекс для ключа рендеринга цикла списка
Например
变化前数组的值是[1,2,3,4],key就是对应的下标:0,1,2,3
变化后数组的值是[4,3,2,1],key对应的下标也是:0,1,2,3
- Затем алгоритм diff находит значение ключа = 0 в массиве до изменения, равное 1, и значение ключа = 0, найденное в массиве после изменения, равно 4
- Повторно удалить и обновить, потому что дочерние элементы отличаются
- Но если добавляется уникальный ключ, следующим образом
变化前数组的值是[1,2,3,4],key就是对应的下标:id0,id1,id2,id3
变化后数组的值是[4,3,2,1],key对应的下标也是:id3,id2,id1,id0
- Затем алгоритм сравнения находит значение key=id0 в массиве до изменения, равное 1, и значение key=id0, найденное в массиве после изменения, также равно 1.
- Поскольку дочерние элементы одинаковы, они не будут удаляться и обновляться, а только перемещаться, что повышает производительность.