Описване на props с PropTypes идващи от HOC от външна библиотека

Fakeheal
Гуру
Гуру
Posts: 2703
Joined: Sat Apr 17, 2010 6:37 am
Answers: 351
Location: /r/eyebleach
Contact:

Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Fakeheal » Thu Apr 02, 2020 11:30 pm

Използвам i18next (и пакета им за reactjs) и имам class component, който ползва i18next - withTranslation:

Code: Select all

import React, { Component } from 'react';
import { withTranslation } from 'react-i18next';

class Home extends Component {
  constructor(props) {
    super(props);
    // some default values are set here
  }

  componentDidMount() {
    // some http requests are happening here
  }

  render() {
    const { t } = this.props;
    return (
      <h1>{t('pageHome:title')}</h1>
    );
  }
}

export default withTranslation()(Home);
Също така съм си сложила linter-a за js & react на airbnb и от него получавам грешка:
ESLint: t is missing in props validation (react/prop-types)
Защото t идва от HOC: withTranslation()

Единствения начин, по който мога да я премахна е с:

Code: Select all

Home.propTypes = {
  t: PropTypes.func.isRequired,
};
Но не съм сигурна, че това е правилния начин. Няма ли някак си linter-a да разбере, че prop-a идва от Higher Order Component-a от package-a
by Revelation » Sat Apr 04, 2020 4:32 pm
1. Hooks ти помагат да достъпиш API-а на доста по-ниско ниво и ти дава повече свобода и контрол.

2. Забравяш за Stateful/Stateless компоненти. Всеки компонент може да е stateful или stateless по всяко време без да се налага да преминаваш от функционален компонент към класов. Вземи следния случай: в един момент доста stateless компоненти трябва всъщност да контролират даден state, иначе всичко трябва да се подава надолу чрез props и така родителския компонент е затрупан със стейт, който не му е в контекста. Чрез hooks, не е нужно да променяш функционалния компонент към класов. А и както знаеш, класовите компоненти се водят stateful и добавят допълнителен overhead към приложението. Чрез hooks не е така, защото в случая няма да използваш никой от lifecycle методите, а просто ще добавиш стейт към компонента.

3. Премахваш класовете. Изцяло можеш да пишеш фунционално. Това ще окаже ефект и върху размера на бъндъла, защото babel няма да има нужда да прави магии да конвертира класове към функции(което накрая се отразява в повече код отколкото е нужно).

4. State-а се управлява много по-лесно. Забравяш за nested object state, когато имаш голям компонент, който трябва да контролира голям брой стейтове. Също, когато стейта е nested, много по-лесно се контролира без да се налага да използваш nested spreading, докато стигнеш до обекта, който искаш да промениш.

5. useEffect() замества повечето lifecycle методи - componentDidMount(), componentWillUpdate() и т.н. Предимството е, че можеш да имаш колкото искаш useEffect() с различна логика, която да контролира ъпдейтването на компонента.

6. Momoization-а прави нещата доста удобни. Лесно можеш да "кешираш" тежки таскове, когато нещо изисква изчисления (computation), което прави компоненти доста по-леки.

7. Лесно се създават custom hooks, които помагат доста с decoupling на приложението. Много неща могат да се изведат като hooks и използват, когато са нужни. Да речем използваш Axios за заявки към API. Всичко добре, обаче искаш, когато нещо се зарежда (изчакване на отговор от сървъра) да контролираш някой spinner и когато е готово да изведеш резултатите.
В много от случаите добавяш още state към компонента, за да контролираш зареждането. Е, да, но това в един момент трябва да го добавиш на повечето компоненти и да контролираш стейта за всеки един компонент.
В този случай, можеш да си създадеш hook, да речем useAxios(), който вътршно контролира стейта за зареждане и ти просто го връщаш на компонента използващ този hook.

Code: Select all

function Home() {
    let [isLoading, data] = useAxios(url);
}
При зареждане на компонента useAxios(url) ще се задейства, ще направи рикуеста и ще ъпдейтва isLoading и data при всяка настъпила промяна.
Така стейта си стои в useAxios hook-а, а стейта на компонента остава чист и само по предназначение.

Може да има още причини, но не се сещам да допълня.

=======================

Колкото до решението, можеш да направиш и друго.
Просто направи нов компонент, който екстендва Component - да речем TranslationComponent и сложи тази логика там.

Code: Select all

import { Component } from "react";
import PropTypes from "prop-types";
import {withTranslation} from "react-i18next";

class TranslationComponent extends Component
{
    constructor(props) {
        super(props);

        const { t } = this.props;
        this.t = t;
    }
}

TranslationComponent.propTypes = {
    t: PropTypes.func.isRequired
};

export default withTranslation()(TranslationComponent);

Code: Select all

import React from 'react';
import TranslationComponent from "./TranslationComponent";

class Home extends TranslationComponent {
    constructor(props) {
        super(props);
        // some default values are set here
    }

    componentDidMount() {
        // some http requests are happening here
    }

    render() {
        const t = this.t;
        return (
            <h1>{t('pageHome:title')}</h1>
        );
    }
}

export default Home;
Понеже в случая wrap-ваш TranslationComponent не съм сигурен при грешка как ще изглежда stack trace-а, но би трябвало да получиш информация от кой компонент идва проблема.
Go to full post

User avatar
Revelation
Web-tourist
Web-tourist
Posts: 861
Joined: Sun Mar 24, 2013 1:23 pm
Answers: 62

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Revelation » Fri Apr 03, 2020 11:44 pm

Имаш и други варианти. Зависи от целта, която искаш да постигнеш.

Ако използваш prop types и на други места, то тогава единия вариант е начина, по който ти си подтиснала грешката.

Ако не искаш да използваш prop types, но искаш да подтиснеш линтера е, то можеш да игнорираш проверката с коментар:

Code: Select all

/* eslint-disable-next-line */
const { t } = this.props;

Code: Select all

const { t } = this.props; // eslint-disable-line
или https://eslint.org/docs/user-guide/conf ... e-comments

Друг вариант е да модифицираш .eslintrc и да изключиш това правило или да го направиш warning, но ако това е единичен случай, ти препоръчвам да използваш inline коментарите или просто да си го дефинираш.

Иначе линтера няма как да разбере това. Реакт също не го интересува това. t в случая е в контекста на Home компонента, а не на HOC-то и линтера те предупреждава, че имаш нов prop, който не е дефиниран.

Имай предвид, че airbnb правилата са много стриктни. Сигурна ли си, че точно тях искаш да използваш?

User avatar
Revelation
Web-tourist
Web-tourist
Posts: 861
Joined: Sun Mar 24, 2013 1:23 pm
Answers: 62

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Revelation » Sat Apr 04, 2020 12:05 am

Между другото, защо не използваш hooks?

Fakeheal
Гуру
Гуру
Posts: 2703
Joined: Sat Apr 17, 2010 6:37 am
Answers: 351
Location: /r/eyebleach
Contact:

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Fakeheal » Sat Apr 04, 2020 1:30 pm

Мерси за предложенията, за съжаление не е единичен случай, т.к. много части трябват да имат преведени стрингове.

Също така кода трябва да е compatible с линтера на airbnb (стриктни правила == малко проблеми в големи екипи).

Направих си един обект, който екстендвам в проптайпс на компонентите, които използват i18next, за да не трябва да пиша всеки път, че е задължителна функция. : )

Не ползвам hooks, защото проекта е започнат преди създаването им.

User avatar
Revelation
Web-tourist
Web-tourist
Posts: 861
Joined: Sun Mar 24, 2013 1:23 pm
Answers: 62

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Revelation » Sat Apr 04, 2020 2:01 pm

Предполагам поради consistency reasons нямате право да променяте към functional components?

Ако има вариант за смяна, силно препоръчвам да минете на hooks. И в твоя случай ще трябва да използваш само useTranslation без това да се подава като prop на компонента, което ще намали props check-а, за неща, които не са реално пряко свързани с компонента (като t).

Ако не, магическата пръчка. :D

Може ли пример какво точно си направила, че ми стана интересно.

Fakeheal
Гуру
Гуру
Posts: 2703
Joined: Sat Apr 17, 2010 6:37 am
Answers: 351
Location: /r/eyebleach
Contact:

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Fakeheal » Sat Apr 04, 2020 3:24 pm

Мхм, проекта е на финална права. Предполагам в бъдеще ще инвестират време и в това, но не съм сигурна.

Какви са предимствата на hooks пред class компонентите?

Аз от скоро се занимавам с React и на теория разбирам нещата, но имам много малко опит и "this vs. that" са ми тъмна Индия.

Това, което направих накратко е:

src/utilities/propTypes.js

Code: Select all

import PropTypes from 'prop-types';

export const hasTranslations = {
  t: PropTypes.func.isRequired,
};
src/Home.jsx:

Code: Select all

Home.propTypes = {
  ...hasTranslations,
  otherProp: PropTypes.string.isRequired,
};
Изглежда ми по-изчистено и self-describing от t: PropTypes.func.isRequired на всяко. едно. място. Ще видим дали ще мине CR. :D

User avatar
djman
Гуру
Гуру
Posts: 2796
Joined: Sat Sep 12, 2009 8:07 am
Answers: 107

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by djman » Sat Apr 04, 2020 4:29 pm

Според мен hooks и въобще functional components правят кода по-изчистен, и съответно, разбираем.

Ще добавя и че използването на типизиран език (например typescript) си е задължително ако проекта има повече от 2 компонента.

User avatar
Revelation
Web-tourist
Web-tourist
Posts: 861
Joined: Sun Mar 24, 2013 1:23 pm
Answers: 62

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Revelation » Sat Apr 04, 2020 4:32 pm

1. Hooks ти помагат да достъпиш API-а на доста по-ниско ниво и ти дава повече свобода и контрол.

2. Забравяш за Stateful/Stateless компоненти. Всеки компонент може да е stateful или stateless по всяко време без да се налага да преминаваш от функционален компонент към класов. Вземи следния случай: в един момент доста stateless компоненти трябва всъщност да контролират даден state, иначе всичко трябва да се подава надолу чрез props и така родителския компонент е затрупан със стейт, който не му е в контекста. Чрез hooks, не е нужно да променяш функционалния компонент към класов. А и както знаеш, класовите компоненти се водят stateful и добавят допълнителен overhead към приложението. Чрез hooks не е така, защото в случая няма да използваш никой от lifecycle методите, а просто ще добавиш стейт към компонента.

3. Премахваш класовете. Изцяло можеш да пишеш фунционално. Това ще окаже ефект и върху размера на бъндъла, защото babel няма да има нужда да прави магии да конвертира класове към функции(което накрая се отразява в повече код отколкото е нужно).

4. State-а се управлява много по-лесно. Забравяш за nested object state, когато имаш голям компонент, който трябва да контролира голям брой стейтове. Също, когато стейта е nested, много по-лесно се контролира без да се налага да използваш nested spreading, докато стигнеш до обекта, който искаш да промениш.

5. useEffect() замества повечето lifecycle методи - componentDidMount(), componentWillUpdate() и т.н. Предимството е, че можеш да имаш колкото искаш useEffect() с различна логика, която да контролира ъпдейтването на компонента.

6. Momoization-а прави нещата доста удобни. Лесно можеш да "кешираш" тежки таскове, когато нещо изисква изчисления (computation), което прави компоненти доста по-леки.

7. Лесно се създават custom hooks, които помагат доста с decoupling на приложението. Много неща могат да се изведат като hooks и използват, когато са нужни. Да речем използваш Axios за заявки към API. Всичко добре, обаче искаш, когато нещо се зарежда (изчакване на отговор от сървъра) да контролираш някой spinner и когато е готово да изведеш резултатите.
В много от случаите добавяш още state към компонента, за да контролираш зареждането. Е, да, но това в един момент трябва да го добавиш на повечето компоненти и да контролираш стейта за всеки един компонент.
В този случай, можеш да си създадеш hook, да речем useAxios(), който вътршно контролира стейта за зареждане и ти просто го връщаш на компонента използващ този hook.

Code: Select all

function Home() {
    let [isLoading, data] = useAxios(url);
}
При зареждане на компонента useAxios(url) ще се задейства, ще направи рикуеста и ще ъпдейтва isLoading и data при всяка настъпила промяна.
Така стейта си стои в useAxios hook-а, а стейта на компонента остава чист и само по предназначение.

Може да има още причини, но не се сещам да допълня.

=======================

Колкото до решението, можеш да направиш и друго.
Просто направи нов компонент, който екстендва Component - да речем TranslationComponent и сложи тази логика там.

Code: Select all

import { Component } from "react";
import PropTypes from "prop-types";
import {withTranslation} from "react-i18next";

class TranslationComponent extends Component
{
    constructor(props) {
        super(props);

        const { t } = this.props;
        this.t = t;
    }
}

TranslationComponent.propTypes = {
    t: PropTypes.func.isRequired
};

export default withTranslation()(TranslationComponent);

Code: Select all

import React from 'react';
import TranslationComponent from "./TranslationComponent";

class Home extends TranslationComponent {
    constructor(props) {
        super(props);
        // some default values are set here
    }

    componentDidMount() {
        // some http requests are happening here
    }

    render() {
        const t = this.t;
        return (
            <h1>{t('pageHome:title')}</h1>
        );
    }
}

export default Home;
Понеже в случая wrap-ваш TranslationComponent не съм сигурен при грешка как ще изглежда stack trace-а, но би трябвало да получиш информация от кой компонент идва проблема.

User avatar
Ticketa
Турист
Турист
Posts: 469
Joined: Mon Feb 27, 2012 1:54 pm
Answers: 23
Location: in /root
Contact:

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Ticketa » Sat Apr 04, 2020 6:01 pm

офтопик:
Абе пичове и момичета, на какъв език говорите тука :D 3 пъти прочетох цялата тема и нищо не разбрах. Reac (framework) рамката ли става въпрос? Май ще залягам яко над тетрадките :shock: :shock: :shock: хвърлете някакви уроци ще са от ползва , стига да имате време :dance: :dance: :dance:

User avatar
Revelation
Web-tourist
Web-tourist
Posts: 861
Joined: Sun Mar 24, 2013 1:23 pm
Answers: 62

Re: Описване на props с PropTypes идващи от HOC от външна библиотека

Post by Revelation » Sat Apr 04, 2020 10:16 pm

Ticketa wrote:
Sat Apr 04, 2020 6:01 pm
офтопик:
Абе пичове и момичета, на какъв език говорите тука :D 3 пъти прочетох цялата тема и нищо не разбрах. Reac (framework) рамката ли става въпрос? Май ще залягам яко над тетрадките :shock: :shock: :shock: хвърлете някакви уроци ще са от ползва , стига да имате време :dance: :dance: :dance:
Всъщност, React не е framework (като Vue и Angular), а библиотека.

За материали започни от официалния сайт.

Post Reply