The solution to the absence of prevProps in getDerivedStateFromProps

  • Tutorial

Hello friends!


So, the React developers decided to make our work with their library more linear, to send, so to speak, negligent people to the path of the least chance to make a mistake and write bad code, which, in my opinion, is our inalienable right and way to improve and invent. We are talking about all the favorite methods of componentWillReceiveProps and others from the same series; they will no longer be there, but we will be given an alternative in the form of the static method getDerivedStateFromProps. Personally, he reminds me of a dark room where things are lying, and they need to be found, but nothing is visible.


Developers in their responses to angry comments of users of the React write they say: Well, we will not give you prevProps, this is impossible, think up something, prevProps are not there, well, you stick there, just cache them in a state, in general they suggest that we make a small crutch in our new good code. Of course, this is all easy, you can understand and forgive, but now I was annoyed by the fact that now I don’t have this context, my room was bricked up, nothing was visible, I couldn’t even hear my neighbors, so I decided to write something for myself It will hide all crutches and my code will look albeit strange, but boneless (is it boneless?).


In general, I need to implement prevProps into the component state, I still want everything to look as usual, and also it’s impossible to live without the magic this in static getDerivedStateFromProps (here is a fool!). Two days of torment and self-improvement and everything is ready, I gave birth to a mouse.


Installation


npm install--save state-master

Using


Just write the same getDerivedStateFromProps and componentDidUpdate, but already modified.
We wrap our component in "withStateMaster", we transfer there the list of "props", which changes need to be monitored


import {Component} from'react'import {withStateMaster, registerContext, unregisterContext} from'state-master';
// Список "пропсов", изменения которых нужно отслеживатьconst PROP_LIST = ['width', 'height', 'bgColor', 'fontSize', 'autoSize'];
// или просто строка, если только одно значениеconst PROP_LIST = 'value';
// добавление начального состояния опциональноconst INITIAL_STATE = {
  width: 1000,
  height: 500
};
classContainerComponentextendsComponent{
  static displayName = 'Container';
  static getDerivedStateFromProps(data) {
    const {
        nextProps,
        prevProps,
        state,
        isInitial,
        changed,
        changedProps,
        isChanged,
        add,
        addIfChanged,
        isChangedAny,
        addIfChangedAny,
        isChangedAll,
        call,
        get
      } = data;
      // ниже пойдет речь об изменившихся пропсах, это только те, которые были указаны в массиве PROPS_LIST// метка о том, что это первый вызов после конструктораif (isInitial) {
        // добавляем поле "name" с нужным значением "value" к возвращаемому изменению состояния
        add('name', value);
        // добавляем поле "name" со значением взятым из пришедших пропсов
        add('name');        
      }
      // changedProps это массив, который содержит имена всех поменявшихся пропсовif (changedProps.indexOf('value') !== -1) {
        add('value'); 
      }
      // возвращает true если данный prop как-либо изменилсяif (isChanged('autoSize')) {
        add('autoSize');
      }      
      // возвращает true если данный prop изменился на указанное значение (здесь на true)if (isChanged('autoSize', true)) {
        add('autoSize', true);
      }
      // changed является true, если один из пропсов как-либо изменилсяif (changed) {
        add('somethingChanged', true);
      }
      // возвращает true, если один из пропсов как-либо изменился// работает так же, как и пример вышеif (isChangedAny()) {
         add('somethingChanged', true);
      }
      // возвращает true, если один из указанных пропсов как-либо изменилсяif (isChangedAny('bgColor', 'fontSize', ...)) {
        const {bgColor, fontSize} = nextProps;
        add('style', {bgColor, fontSize});
      }
      // возвращает true, если все пропсы из списка PROPS_LIST как-либо изменилисьif (isChangedAll()) {
        add('allChanged', true);
      }
      // возвращает true, если все из указанных пропсов как-либо изменилисьif (isChangedAll('width', 'height', ...)) {
        const {width, height} = nextProps;
        add('size', width + 'x' + height);
        // вызывает функцию с таймаутом// то же самое, что и setTimeout(() => this.changeSomething(), 0);// используйте для каких-либо действий, которые нужно выполнить по завершению апдейта компонента// хотя правильнее располагать этот вызов в componentDidUpdate
        call(() => {
          this.initNewSizes(width, height);
        });
      }
      // вызывает метод "add", если указанный prop как-либо изменился
      addIfChanged('name', value);
      addIfChanged('name');
      // вызывает метод "add", если какой-либо prop из списка PROPS_LIST как-либо изменился
      addIfChangedAny('name', value);
      addIfChangedAny('name');
      // возвращает объект изменения состояния или null// нужно для отладки, чтобы знать, что ушло в состояние// располагайте в концеconsole.log(get());
      // если вы использовали метод "add", то возвращать ничего не нужно// или вы можете просто вернуть объект, как и обычно без всяких вызовов "add"return {
        size: nextProps.width + 'x' + nextProps.height
      }
  }
  constructor(props) {
    super(props);
    // используйте "registerContext", если вам необходим this контекст в getDerivedStateFromProps// если компонент наследуется от другого, в котором был вызван "registerContext", то здесь этого делать не нужно
    registerContext(this);
  }
  // данный метод также будет модифицирован
  componentDidUpdate(data) {
    const {
        prevProps,
        prevState,
        snapshot,
        changedProps,
        changed,
        isChanged,
        isChangedAny,
        isChangedAll
      } = data;
      if (isChanged('value')) {
        const {value} = this.props;
        this.doSomeAction(value);
      }
  }
  componentWillUnmount() {
    // также добавляйте этот код, если "registerContext" был вызван в конструкторе
    unregisterContext(this);
  }
  render() {
    const {style, size} = this.state;
    return (
      <divclassName="container"style={style}>
        Size is {size}
      </div>
    )
  }
}
exportconst Container = withStateMaster(ContainerComponent, PROP_LIST, INITIAL_STATE);

If the component is inherited from another, pass the parent so that the parent getDerivedStateFromProps is called.


exportconst Container = withStateMaster(ContainerComponent, PROP_LIST, null, ParentalComponent);

This is my solution to this problem (although perhaps I didn’t understand the reaction enough, and this is not a problem at all).


Thus, I entered into resistance to the new canons of React, maybe someday I will accept and rewrite everything as it should.


Although the developers may again redo everything and there will be other pressing issues.
Everything, I lie down, and lying, as they say, do not beat.


Also popular now: