В те годы я не отвечал на вопросы о реакции, которые придумывал.

React.js

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.
  • Поскольку дочерние элементы одинаковы, они не будут удаляться и обновляться, а только перемещаться, что повышает производительность.