Ответы пользователя по тегу React
  • Как правильно назначить пути для react router?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Можно передавать переменную c базовым URL с помощью webpack.DefinePlugin или любым другим удобным способом. При использовании create-react-app удобно воспользоваться .env файлом.
    Базовый URL передатется в роутер с помощью свойства basename.

    Пример с переменной .env:
    <BrowserRouter basename={process.env.REACT_APP_BASE_URL} />
    Ответ написан
    Комментировать
  • Как правильно отлавливать ошибки в react 16.x?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Оборачивайте дочерний компонент, в котором может возникнуть ошибка, в ErrorBoundary. Никакого особого механизма всплытия ошибок нет.
    Ответ написан
    4 комментария
  • Как вывести все name из объектов в массиве (jsonplaceholder)?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Рекомендую прежде чем начинать что-либо писать, хорошо изучить возможности библиотеки или хотя бы прочитать Tutorial и разделы Main Concepts и Advanced Guides официальной документации.
    То, что вы хотите реализовать правильно делается так.
    Ответ написан
    1 комментарий
  • Как правильно делать fetch в react?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. data.goals[0].gs_id
    Использование подобных, небезопасных конструкций считается плохим тоном.
    2. Используйте в state ключ состояния загрузки.
    export default class Forma extends React.Component {
        constructor(props) {
            super(props);
    
            this.state ={ data: {}, isFetching: true, error: null };
        }
    
        componentDidMount() {
            fetch('http://localhost:3001')
                .then(response => response.json())
                .then(result => this.setState({data: result, isFetching: false }));
                .catch(e => {
                  console.log(e);
                  this.setState({data: result, isFetching: false, error: e }));
                });
        }
    
        render() {
            const { data, isFetching, error } = this.state;
            
            if (isFetching) return <div>...Loading</div>;
    
            if (error) return <div>{`Error: ${e.message}`}</div>;
    
            return <h1>{data.goals[0].gs_id}</h1>;
        }
    
    
    }
    Ответ написан
    9 комментариев
  • Правильно я визуализировал работу под капотом в Redux+ReactRedux после Reducer?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Все происходит совсем не так. Вы, видимо, пытаетесь угадать, а достаточно лишь изучить исходный код библиотеки react-redux и почитать про метод store.subscribe redux.

    redux и react-redux это две ничем не связанные и не подозревающие о существовании друг друга библиотеки. Компоненты react-redux лишь используют API объекта store из redux, который вы должны передать в Provider сами.
    Когда вы подключаете react-redux вы используете компонент Provider и HOC connect. Ниже перечислены их основные функции.

    Provider:
    1. Получает в props store и подписывается на его обновления с помощью store.subscribe.
    2. Инициирует перерисовку дочернего древа по обновлению store, с помощью вызова this.setState.
    3. Передает в контекст store и storeState(результат вызова store.getState())

    HOC connect:
    1. Передает нужные props в оборачиваемый компонент с помощью, полученного через контекст, состояния и маппера mapStateToProps.
    2. Оборачивает actions в вызов store.dispatch с помощью store, полученного через контекст, и маппера mapDispatchToProps, либо просто передает store.dispatch в props компонента как свойство dispatch.
    3. Если аргумент mapStateToProps был передан, то компонент-обертка, возвращенный вызовом connect, отслеживает обновления store. Если свойства полученные из store и props не были изменены, а компонент уже отрисован, то connect при обновлении возвращает сохраненный по ссылке отрисованный компонент, если изменения были, то дочерний компонент перерисовывается. Логику обновления можно понять, взглянув на функцию, результат вызова которой, вызывается в render компонента обертки:
    function makeChildElementSelector() {
      let lastChildProps, lastForwardRef, lastChildElement
    
      return function selectChildElement(childProps, forwardRef) {
        if (childProps !== lastChildProps || forwardRef !== lastForwardRef) {
          lastChildProps = childProps
          lastForwardRef = forwardRef
          lastChildElement = (
            <FinalWrappedComponent {...childProps} ref={forwardRef} />
          )
        }
    
        return lastChildElement
      }
    }


    Подробнее: react-redux with Dan Abramov
    Ответ написан
    Комментировать
  • Как правильно сделать import обычного класса в React компонент?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Ошибка линтера no-unused-expressions. Импортируете модуль, но не используете.

    Учитесь читать и понимать тексты ошибок, а так же самостоятельно гуглить решения проблем. Для этого достаточно вбить в поисковике текст ошибки.
    Ответ написан
    4 комментария
  • Как правильно писать на jsx?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Код надо транслировать в JS перед выполнением.
    babel-preset-react
    Ответ написан
    2 комментария
  • Почему не наследуются props через redux метод connect в в компонент App?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    /* ... */
    
    const mapStateToProps = state => ({
      desks: state.desks,
    });
    
    const ConnectedApp = ReactRedux.connect(mapStateToProps)(App);
    
    ReactDOM.render(
      <ReactRedux.Provider store={store}>
        <ConnectedApp />
      </ReactRedux.Provider>, 
      document.querySelector('#root'),
    );
    Ответ написан
    Комментировать
  • Нормален ли данный подход рендеринга через setState?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Если вам по клику в шапке одной из досок, надо обновлять какое-либо состояние на уровне приложения, то, думаю, тут лучше подойдет redux.
    В других случаях, например на уровне модуля, lifting up state считается хорошей практикой.
    Ответ написан
    4 комментария
  • Context API можно использовать вместе Redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Context API можно использовать вместе Redux?

    Можно и нужно.

    И по нажатию на одну из этих кнопок, у меня должна выскакивать модалка с формой.

    Глобальные модалки лучше через Redux.

    Если данный кейс не корректен, то можете привести примеры когда целесообразнее использовать Context API, чем пихать инфу в Redux?

    Темы, локали, UA все это удобней использовать с Context API
    Ответ написан
    2 комментария
  • React + Redux, как записать в состояние после того как придут данные?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    static getDerivedStateFromProps(props, state) {
      if (props.visas[0] !== state.visa) {
        return {
          visa: props.visas[0],
        };
      }
    
      return null;
    }

    Массив this.props.visa должен существовать всегда.
    Ответ написан
    Комментировать
  • Является ли хорошей практикой использовать setState в redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    По-хорошему в redux выносят только то, что используется в разных частях приложения, а так же данные полученные с сервера. Для остального предпочтительней использовать state компонента. В подавляющем большинстве случаев, lifting state up будет предпочтительней использования redux.

    Ответ Дэна Абрабомова на похожий вопрос How to choose between Redux's store and React's state.
    Ответ написан
    2 комментария
  • Как правильно перечислить класс в шаблоне?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Это, пожалуй, наихудший путь которым только можно пойти.
    Реализация компонента по-хорошему должна быть инкапсулирована, а вы должны работать с его интерфейсом.
    <Button
      type="outline"
      size="sm"
      color="succes"
      disabled={isButtonDisabled}
      onClick={handleClick}
    >
      Succes
    </Button>
    Ответ написан
    Комментировать
  • Как организовать для работы список файлов и папок с уровнем вложенность в обьекте?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Что-то вроде:
    [
      {
        name: 'some_name',
        type: 'folder',
        isHidden: false,
        size: 23123,
        created_at: 4342323434,
        edited_at: 3453123434,
        path: '/some_place/some_name',
        children: [],
        childrenLength: 4,
        access_rights: [],
      },
      {
        name: 'some_image.png',
        type: 'file',
        isHidden: false,
        size: 23123,
        created_at: 4342323434,
        edited_at: 3453123434,
        path: '/some_place/some_image.png',
        access_rights: [],
      },
    ]
    Ответ написан
    Комментировать
  • Как правильно использовать mapStateToProps с асинхронным поведением компонента?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Не надо обрабатывать подобные вещи в mapStateToProps. Оставьте просто:
    const mapStateToProps = (state, ownProps) => ({
      coin: coinSelector(state, ownProps),
      isLoading: isCoinsLoadingSelector(state),
    });

    В методе render:
    render() {
      const { coin, isLoading } = this.props;
    
      if (isLoading) return <Preloader />;
    
      if (!isLoading && !coin) return <NotFound />;
    
      return <CoinDetails coin={coin} />;
    }

    Учитесь проектировать хранилище, задавать начальное состояние и писать render метод так, чтобы он успешно выполнялся вне зависимости от того получили вы необходимые данные или нет.
    Ответ написан
    4 комментария
  • Возможно ли получить элемент массива из состояния redux, используя mapStateToProps?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    const coinSelector = (state, ownProps) =>
      state.coins.data.find(coin => coin.symbol === ownProps.match.params.id);
    
    const mapStateToProps = (state, ownProps) => ({
      coin: coinSelector(state, ownProps),
    });
    Ответ написан
    Комментировать
  • Нужно ли изучать шаблонизаторы, если планирую использовать ReactJS?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    На то, чтобы вкатиться в тему уйдет час-три. Знания полезные. Достаточно просто попробовать базовые вещи. Зазубривать API шаблонизатора, которым не факт, что будете когда-нибудь пользоваться, не стоит.
    Ответ написан
    Комментировать
  • Disable кнопки после обновления redux store?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Очевидно, что так:
    render() {
        return (
          <SubList d={visibility}>
            {list.map((item, i) => (
              <Button
                key={i.toString()}
                onClick={this.handleClick}
                disabled={item.isLoading}
              />
            ))}
          </SubList>
        );
      }
    Ответ написан
  • Оценка своего уровня. Как улучшить код?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. Используйте const вместо let для определения переменных которые не переопределяются в коде. Это помогает снизить когнитивную нагрузку с человека читающего код и негласный стандарт в React разработке.

    2. Такие вещи как globalStyles и конфигурацию store лучше вынести в отдельные файлы. Они могут со временем хорошо разрастись.
    По поводу globalStyles, вы вообще можете вынести их в отдельный css файл.

    3. Вместо:
    {
      isModal
      ? <Route path="/auth" component={AuthPopup} />
      : null
    }

    лучше:
    {isModal && <Route path="/auth" component={AuthPopup} />}


    4. Вместо:
    function mapDispatchToProps(dispatch) {
        return {
            autoLogin: () => dispatch(autoLogin()),
            getBrowser: () => dispatch(getBrowser()),
            getMedia: () => dispatch(getMedia())
        }
    }


    лучше:
    const mapDispatchToProps = {
      autoLogin,
      getBrowser,
      getMedia,
    };


    5. Точки с запятыми в конце то есть, то нет. Определитесь и приведите код к одному виду.

    6.
    & label {}
    & input {}
    & span {}

    Это не очень хороший подход. Во-первых ваши стили не изолированные, что может приводить к неожиданным результатам. Во-вторых у вас очень много дублирования стилей. Определите Input и Label как базовые компоненты и используйте в разных местах, то же с остальным если есть.

    7. Почему папка со страницами называется Containers? Дань бойлерплейтам?

    8. Использование trailing comma является хорошей практикой.

    9.
    import {combineReducers} from 'redux';
    import photoReducer from './photoReducer';
    import authReducer from './authReducer';
    import globalReducer from './globalReducer';
    
    export default combineReducers({
        photoReducer, authReducer, globalReducer
    })


    Все таки приятней работать с хранилищем в котором ключи не имеют в названии слова reducer:
    import {combineReducers} from 'redux';
    import photo from './photoReducer';
    import auth from './authReducer';
    import global from './globalReducer';
    
    export default combineReducers({
      photo, 
      auth,
      global,
    });


    10. Забудьте вообще, что в языке есть возможность использовать вложенный тернарный оператор:
    return e === 'invalid-email' ? 'Неверно указан e-mail'
        : e === 'user-not-found' ? 'Указанный e-mail на найден'
        : e === 'wrong-password' ? 'Неверный пароль'
        : e === 'email-already-in-use' ? 'Указанный e-mail уже используется'
        : e === 'network-request-failed' ? 'Нет подключения к интернету'
        : e === 'operation-not-allowed' ? 'Произошла ошибка, попробуйте снова'
        : e === 'popup-closed-by-user' ? 'Окно авторизации закрыто пользователем'
        : e === 'account-exists-with-different-credential' ? 'Аккаунт уже существует с другими данными, используйте другой способ авторизации'
        : e

    Это одна из самых худших практик в JavaScript разработке. Тут лучше подойдет конструкция switch case

    11. Константы actionTypes лучше вынести в папку constants и разложить по разным файлам, иначе со временем у вас там будет свалка.

    12. Вместо:
    import {SET_ACTIVE, CHANGE_VALUE, SET_DEFAULT, UPLOAD, UPDATE_IMAGE, SET_IMAGE_ERROR, SET_LIKE, SET_COMMENT, ADD_ARTICLE_SUCCESS, FETCH_ARTICLES_START, FETCH_ARTICLES_SUCCESS, FETCH_ARTICLES_ERROR} from '../actions/actionTypes';

    Лучше:
    import {
      SET_ACTIVE,
      CHANGE_VALUE,
      SET_DEFAULT, UPLOAD,  
      UPDATE_IMAGE,
      SET_IMAGE_ERROR,
      SET_LIKE,
      SET_COMMENT,
      ADD_ARTICLE_SUCCESS,
      FETCH_ARTICLES_START,
      FETCH_ARTICLES_SUCCESS,
      FETCH_ARTICLES_ERROR,
    } from '../actions/actionTypes';


    13. Попробуйте внедрить библиотеку reselect. И для получения значения из store вместо записи вида:
    function mapStateToProps(state) {
        return {
            browser: state.globalReducer.browser
        }
    }


    использовать селектор:
    const mapStateToProps = state => ({
      browser: browserSelector(state),
    });
    Ответ написан
    12 комментариев