Расскажите о жизненном цикле класса UNSAFE в React v16.3.

внешний интерфейс React.js ESLint

Я не знаю, заметили ли мои друзья, что с тех пор, как React был обновлен до версии 16.3, предыдущая версия использовалаcomponentWillMount,componentWillReceiveProps,componentWillUpdateВсе три функции жизненного цикла имеют оповещения eslint, давайте воспользуемсяUNSAFE_Новые функции жизненного цикла с префиксом. Не могу не задаться вопросом: «Каково намерение реагировать»? зачем добавлятьUNSAFE_приставка?

Почему вы предупреждаете эти функции жизненного цикла?

1. КомпонентУиллМаунт

componentWillMountЖизненный цикл происходит до первого рендеринга, и большинство часто используемых малых партнеров инициализируют данные здесь или асинхронно получают назначения внешних данных. Инициализировать данные, реагировать официально рекомендует размещать их вconstructorв. И асинхронное получение внешних данных, рендеринг не ждет возврата данных перед рендерингом.

Случай 1: Ниже приведен пример компонента, который прослушивает внешний планировщик событий во время установки.

class Example extends React.Component {   
    state = {
        value: ''
    };
    componentWillMount() {    
        this.setState({       
            value: this.props.source.value
        });       
        this.props.source.subscribe(this.handleChange);
    }   
    componentWillUnmount() {    
        this.props.source.unsubscribe(this.handleChange ); 
    }   
    handleChange = source => {    
        this.setState({
            value: source.value
        });   
    }; 
}

Представьте, что если компонент прерывается при первом рендеринге, он не будет выполняться, потому что компонент еще не закончил рендеринг.componentWillUnmountЖизненный цикл (注:很多人经常认为componentWillMount和componentWillUnmount总是配对,但这并不是一定的。只有调用componentDidMount后,React才能保证稍后调用componentWillUnmount进行清理). следовательноhandleSubscriptionChangeОн все равно будет выполняться после успешного возврата данных.setStateПоскольку компонент был удален, происходит утечка памяти. Поэтому рекомендуется писать асинхронный сбор внешних данных вcomponentDidMountВ течение жизненного цикла это обеспечиваетcomponentWillUnmountЖизненный цикл выполняется при удалении компонента, что позволяет избежать утечек памяти.

Теперь мой друг знает, почему вам нужно его использоватьUNSAFE_componentWillMountзаменятьcomponentWillMountбар(注意:这里的UNSAFE并不是指安全性,而是表示使用这些生命周期的代码将更有可能在未来的React版本中存在缺陷,特别是一旦启用了异步渲染)

2. компонентWillReceiveProps

componentWillReceivePropsЖизненные циклы запускаются при обновлении реквизита. обычно используется дляpropsПараметр состояния обновляется синхронно при обновлении параметра. но если вcomponentWillReceivePropsЖизненный цикл напрямую вызывает некоторые вызовы родительского компонентаsetStateфункция приведет к бесконечному циклу программы.

Случай 2: Ниже приведен подкомпонентcomponentWillReceivePropsПример вызова функции родительского компонента для изменения состояния в

...
class Parent extends React.Component{
    constructor(){
        super();
        this.state={
            list: [],
            selectedData: {}
        };
    }
    
    changeSelectData = selectedData => {
        this.setState({
            selectedData
        });
    }
    
    render(){
        return (
            <Clild list={this.state.list} changeSelectData={this.changeSelectData}/>
        );
    }
}

...
class Child extends React.Component{
    constructor(){
        super();
        this.state={
            list: []
        };
    }
    componentWillReceiveProps(nextProps){
        this.setState({
            list: nextProps.list
        })
        nextProps.changeSelectData(nextProps.list[0]); //默认选择第一个
    }
    ...
}

Как и выше код, вChildкомпонентcomponentWillReceivePropsпозвонить напрямуюParentкомпонентchangeSelectDataобновитьParentкомпонентыstateизselectedDataстоимость. вызоветParentкомпонент перерисовывается, в то время какParentЗапустится повторный рендеринг компонентаChildкомпонентcomponentWillReceivePropsВыполнение функции жизненного цикла. Это приведет к бесконечному циклу. вызвать сбой программы.

Поэтому React официально поставилcomponentWillReceivePropsзаменитьUNSAFE_componentWillReceiveProps, пусть друзья обращают внимание на дефекты при использовании этого жизненного цикла и обращают внимание на то, чтобы избежать его, например, в приведенном выше примере,ChildсуществуетcomponentWillReceivePropsпередачаchangeSelectDataсудить первымlistЕсть ли обновление, а затем определить, следует ли звонить, вы можете избежать бесконечного цикла.

3. компонент будет обновлять

componentWillUpdateЖизненный цикл запускается до обновления представления. Обычно он используется для сохранения некоторых данных перед обновлением представления, чтобы упростить назначение после обновления представления. Случай 3: Ниже приведен случай возврата к текущей позиции полосы прокрутки после загрузки и обновления списка.

class ScrollingList extends React.Component {   
    listRef = null;   
    previousScrollOffset = null;   
    componentWillUpdate(nextProps, nextState) {    
        if (this.props.list.length < nextProps.list.length) {      
            this.previousScrollOffset = this.listRef.scrollHeight - this.listRef.scrollTop;    
        } 
    }   
    componentDidUpdate(prevProps, prevState) {    
        if (this.previousScrollOffset !== null) {      
            this.listRef.scrollTop = this.listRef.scrollHeight - this.previousScrollOffset;  
            this.previousScrollOffset = null;    
        }   
    }   
    render() {    
        return (       
            `<div>` {/* ...contents... */}`</div>`     
        );   
    }   
    setListRef = ref => {    this.listRef = ref;   };
}

из-заcomponentWillUpdateа такжеcomponentDidUpdateСуществует определенная разница во времени между двумя функциями жизненного цикла (componentWillUpdateПосле рендеринга, вычисления и обновленияDOMэлемент, который называется последнимcomponentDidUpdate), если пользователь просто растягивает высоту браузера в этот период времени, тоcomponentWillUpdateвычислительныйpreviousScrollOffsetне точный. если вcomponentWillUpdateпровестиsetStateоперации, возникнет проблема, заключающаяся в том, что при многократном вызове выполняется только одно обновление.setState放существуетcomponentDidUpdate, что гарантирует, что он вызывается только один раз за обновление.

Поэтому реагировать официально рекомендует ставитьcomponentWillUpdateзаменитьUNSAFE_componentWillUpdate. Если вам действительно нужны вышеуказанные случаи, вы можете использовать новую периодическую функцию, добавленную в 16.3.getSnapshotBeforeUpdate. Ниже будут конкретные инструкции, здесь временная распродажа.

Какие есть альтернативы?

1. получить производное состояние из пропса

getDerivedStateFromPropsЭто официальная функция жизненного цикла, недавно добавленная в 16.3.propsВызывается при изменении, а также при повторном рендеринге родительского компонента. он возвращает новыйpropsстоимость.

Случай 4: следующееgetDerivedStateFromPropsПримеры использования

class Example extends React.Component {   
    static getDerivedStateFromProps(nextProps, prevState) { 
        if(nextProps.name !== prevState.name) {
            return {
                name: nextProps.name
            }
        }
    } 
}

можно увидеть,getDerivedStateFromPropsполучить последниеPropsстоимостьnextProps,ПредыдущийstateстоимостьprevStateДва параметра, return возвращает объект для обновленияstate, или вернутьсяnullУказывает, что обновление не требуетсяstate. Чтобы быть осторожным,getDerivedStateFromPropsНе могу получить доступthis, так что если вы хотите идти в ногу сpropsзначение для сравнения, только предыдущееpropsзначение хранится вstateкак зеркальное изображение. У вас должны быть сомнения здесь, почему бы не поставить предыдущийpropsзначение, переданноеgetDerivedStateFromProps? Официальный анализ выглядит следующим образом:

  • в первый звонокgetDerivedStateFromProps(после создания экземпляра),prevPropsпараметры будутnull, надо посетитьprevPropsдобавлено, когдаif-not-nullОсмотр.

  • нет предыдущегоpropsПередал этой функции шаг к освобождению памяти в будущих версиях React. (Если React не нужно передавать предыдущие свойства в жизненный цикл, то ему не нужно хранить предыдущие объекты свойств в памяти.)

Подводить итоги,getDerivedStateFromPropsЭто официальное новое дополнение для заменыcomponentWillReceivePropsстроить планы. Если вы говорите, что ваш проект будет учитывать совместимость с будущей версией, вместо этого рекомендуется использовать ее.getDerivedStateFromProps.

2. getSnapshotBeforeUpdate

getSnapshotBeforeUpdateэто сgetDerivedStateFromPropsВместе новые функции жизненного цикла, добавленные в 16.3. Запускается, когда самое последнее изменение было зафиксировано вDOMПеред элементом, чтобы компонент мог получить текущее значение перед изменением, любое значение, возвращаемое этим жизненным циклом, будет передано в качестве третьего параметра вcomponentDidUpdate. Обычно, когда нам нужно обновитьDOMнужно сохранить передDOMЭтот жизненный цикл используется в текущем состоянии, которое чаще используется дляDOMПолучите положение прокрутки до обновления и восстановите положение прокрутки после обновления. Например, в третьем случае выше,componentWillUpdateЛучшей альтернативой будетgetSnapshotBeforeUpdate,getSnapshotBeforeUpdateприбытьcomponentDidUpdateтолько обновленоDOMэта операция.

Случай 5. Ниже приведена лучшая альтернатива случаю 3.

class ScrollingList extends React.Component {   
    listRef = null;   
    getSnapshotBeforeUpdate(prevProps, prevState) {    
        if (prevProps.list.length < this.props.list.length) {      
            return this.listRef.scrollHeight - this.listRef.scrollTop;    
        } 
        return null;
    }   
    componentDidUpdate(prevProps, prevState, snapshot) {    
        if (snapshot !== null) {      
            this.listRef.scrollTop = this.listRef.scrollHeight - snapshot;   
        }   
    }   
    render() {    
        return (       
            `<div>` {/* ...contents... */}`</div>`     
        );   
    }   
    setListRef = ref => {    this.listRef = ref;   };
}

Наконец, оcomponentWillMount, официальная рекомендация — поместить логическую обработку функции жизненного цикла вcomponentDidMountЗайти внутрь.

Будет ли он совместим с жизненным циклом класса UNSAFE по мере итерации версии React?

План на сайте React таков:

  • 16.3: Введите псевдонимы для небезопасных жизнейUNSAFE_componentWillMount,UNSAFE_componentWillReceivePropsа такжеUNSAFE_componentWillUpdate. (В этом выпуске работают как старые имена жизненного цикла, так и новые псевдонимы.)

  • Будущие выпуски 16.x: дляcomponentWillMount,componentWillReceivePropsа такжеcomponentWillUpdateВключить предупреждения об устаревании. (В этом выпуске работают как старые жизненные имена, так и новые псевдонимы, но старые имена регистрируют предупреждения режима DEV.)

  • 17.0: удаленоcomponentWillMount,componentWillReceivePropsа такжеcomponentWillUpdate. (С этого момента будет работать только новое имя жизненного цикла «UNSAFE_».)

В заключение

На самом деле, так много сказано. Всего два момента:

1. Реагировать реализуетcomponentWillMount,componentWillReceivePropsа такжеcomponentWillUpdateФункция трех жизненных циклов неисправна, относительно легко вызвать сбой. Однако из-за старых элементов мы привыкли использовать некоторые старые и разработчики с жизненным циклом этих функций, поэтому, добавляя к нимUNSAFE_чтобы напомнить тем, кто использует его, чтобы они знали о своих недостатках.

2. React добавляет две новые функции жизненного циклаgetSnapshotBeforeUpdateа такжеgetDerivedStateFromProps, цель состоит в том, чтобы достичь, даже если эти три функции жизненного цикла не используютсяТолько эти три жизненных цикла могут достичьфункция.

пс: эта статьяЧастьОпираясь на справочные статьиReact V16.3 Предстоящие изменения в жизненном цикле