Ответы пользователя по тегу Redux
  • Почему не работает useState?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Какой смысл писать состояние из store в состояние компонента? Используйте состояние из store напрямую.
    Оптимальней всего, в данном случае, где-то хранить состояние фильтра и фильтровать данные из store налету.
    const phoneList = useSelector((state) => state.phoneListReducer.phoneList);
    const [search, setSearch] = useState('');
    const filteredPhoneList = useMemo(
      () => phoneList.filter(phone => phone.includes(search)),
      [search],
    );
    Ответ написан
    4 комментария
  • Почему не происходит добавление в массив?

    rockon404
    @rockon404 Куратор тега Redux
    Frontend Developer
    Не может не добавляться.
    Демо.
    Ответ написан
    Комментировать
  • Внедрение нового модуля?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    прописать логику чата в redux мешая с логикой сервиса

    Зачем мешать? Можно писать в отдельных файлах в каталогах actions, reducers и components. Можно положить в отдельную папку как feature. Можно сделать отдельной точкой входа. Можно подгружать отдельным чанком по требованию.

    или лучше реализовать это отдельным проетом, а потом подключить

    Вам должно быть виднее, что для вас лучше. Путей много.

    Тоже самое касается и бэк части на node

    То же самое касается и части на node.

    Там так же пихать всё в роуты сервиса или можно декомпазировать ?

    Да, можно красиво разбить на модули, так же как и клиентскую часть.
    Ответ написан
    Комментировать
  • Как правильно изменять store в redux?

    rockon404
    @rockon404 Куратор тега Redux
    Frontend Developer
    И есть 3 класса которые унаследуются от этого класса

    В каждом экземпляре у вас создается своя копия хранилища. Зачем?

    Вот этот код некорректный:
    export const getPriceColor = obj => dispatch => {
      const res = getPriceColorApi(obj);
      dispatch({
        type: obj.name,
        payload: res,
      });
    };

    Вы не дожидаетесь ответа сервера.

    Все работает и state меняется, но вот одна проблема, когда я меняю state вызывая функцию mosquitoNet то type экшена (например ADD_MOSQUITO ) приходит во все reducers и все остальные свойства state возвращаются в исходное состояние.

    ADD_MOSQUITO в вашем коде не сбрасывает состояние.

    Кейс:
    default:
      return state;

    возвращает текущее состояние.

    Как можно избежать этого

    Как минимум, разобраться с тем зачем создаете несколько копий состояния. Возможно, это и есть главная ошибка.
    Ответ написан
  • Почему на хостинге при обновлении страницы ReactRouter ошибка 404?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Ответ написан
    Комментировать
  • Правильно ли реализован перехват ошибок?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    По-хорошему, тексты ошибок должен посылать сервер. Ошибки валидации форм по ключам.
    Ответ написан
    Комментировать
  • Как получить доступ к store из редьюсера?

    rockon404
    @rockon404 Куратор тега Redux
    Frontend Developer
    Вам надо использовать middleware. Например redux-thunk
    const action = value => (dispatch, getState) => {
      const otherValue = otherValueSelector(getState());
      
      const payload = calculate(value, otherValue);
    
      dispatch(otherAction(payload));
    };
    Ответ написан
    Комментировать
  • Как использовать redux в разных классах js?

    rockon404
    @rockon404 Куратор тега Redux
    Frontend Developer
    Можно использовать bindActionCreators или собственную обертку над вызовом store.dispatch и импортировать в модули уже подключенные к store действия.
    export const addTrack = (track) => store.dispatch({ type: ADD_TRACK, payload: { track } });

    Для асинхронных запросов, можно использовать redux-thunk.
    Ответ написан
  • Какой подход лучше для фильтрации / сортировки, react/redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. Если у вас 20 объектов, которые никогда не меняются и по факту так и так используются вашим приложением, то их вообще можно загружать/добавлять на стороне сервера и, не делая никаких запросов, а фильтровать данные на стороне клиента.
    2. Если данных много и они могут измениться в любой момент, то надо перезапрашивать по каждому изменению фильтра. Для обработки действий пользователя при этом лучше использовать debounce.
    Ответ написан
  • Нужно ли изучать Redux Hook?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. Пригодится. Но изучать это очень сильно сказано, там их всего три. Пробежаться глазами и запомнить какой для чего.
    2. Каждый свою. Все есть в документации. К тому же вы уже задавали этот вопрос.
    3. Redux Hooks это лишь доступ к redux с помощью хуков.
    4. Хуки полезны там, где вам удобно их использовать. useReducer при подключении Redux вряд ли понадобится.

    я новичок в мире react. что я должен выучить чтобы полноценно знать React-Redux 2019 года.

    Задавать вопросы не связанные с темой топика запрещено правилами сервиса.
    Посмотрите ссылки в ответе к этому вопросу.

    Где можно найти информацию про Redux Hook ?

    Множество информации по теме можно найти в интернете. Достаточно всего лишь вбить необходимый запрос в поисковик. Например:
    redux hooks tutorial
    redux hooks examples
    Ответ написан
  • Почему не приходит состояние в connect()()?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    default:
      return state;

    По-умолчанию редьюсер должен возвращать не измененное состояние.
    Первый аргумент connect правильно называть mapStateToProps
    Ответ написан
  • Где должны выполнятся сложные операции в React / Redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Для сайд-эффектов и вызовов других action принято использовать middleware(redux-thunk, redux-saga). Ничего подобного в редьюсерах быть не должно.
    Редьюсеры должны оставаться чистыми функциями и все вычисления в них должны ограничиваться синхронным обновлением состояния.
    Ответ написан
    Комментировать
  • Как правильно получать данные с сервера в SPA (React + Redux)?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    что делать в этом случае?

    Вам должно быть виднее. Если это данные которые могли измениться, то очевидно, что лучше подтянуть свежие. Если что-то, что меняется редко, то можно проверить наличие в хранилище.
    Еще можно использовать socket соединение и реализовать на сервере логику, чтобы он сам посылал на клиент обновления по мере их появления.
    Ответ написан
    Комментировать
  • Как прокинуть в пропсы компонента данные из store?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. mapStateToProps метод для маппинга данных store в свойства компонента. Никаких Promise там быть не должно.
    Насколько я понял их там и нет, это неправильный mapDispatchToProps переопределяет значения, так как возвращает одноименные свойства.

    2. Вызов mapDispatchToProps у вас написан неправильно. Вы просто вызываете actions и возвращаете promise. Еще он переопределяет свойства из mapStateToProps.
    Правильно так:
    const mapDispatchToProps = dispatch => ({
      getMovies: () => dispatch(getMoviesAction()),
      getRecommendations: () => dispatch(getRecommendationsAction()),
    });

    или:
    const mapDispatchToProps = {
      getMovies: getMoviesAction,
      getRecommendations: getRecommendationsAction,
    };


    3. Названия действий лучше изменить:
    getMoviesAction ==> getMovies
    getMovies ==> getMoviesSucceeded


    После переименования actions, mapDispatchToProps сокращается до:
    const mapDispatchToProps = {
      getMovies,
      getRecommendations,
    };
    Ответ написан
    1 комментарий
  • Как использовать useStore, useSelector, useDispatch hook?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    1. useDispatch - получение функции store.dispatch в компоненте. Раньше для вызова action функциональный компонент приходилось оборачивать в вызов connect:
    const Foo = ({ dispatch }) => {
      const handler = useCallback(() => {
        dispatch(action());
      }, []);
    
      return (
        <Bar onClick={handler} />
      );
    };
    
    export default connect()(Foo);


    Сейчас:
    const Foo = () => {
      const dispatch = useDispatch();
    
      const handler = useCallback(() => {
        dispatch(action());
      }, []);
    
      return (
        <Bar onClick={handler} />
      );
    };
    
    export default Foo;


    2. useSelector - маппинг значения из store.
    Раньше:
    const Foo = ({ value }) => {
      return (
        <Bar value={value} />
      );
    };
    
    const mapStateToProps = state => ({
      value: state.value,
    });
    
    export default connect(mapStateToProps)(Foo);


    const Foo = () => {
      const value = useSelector(state => state.value);
    
      return (
        <Bar value={value} />
      );
    };
    
    export default Foo;


    3. useStore - получение store целиком:
    const valueSelector = state => state.value;
    
    const Foo = () => {
      const { dispatch, getState, subscribe } = useStore();
      const value = valueSelector(getState());
      
      useEffect(() => subscribe(console.log), []);
    
      const handler = useCallback(() => {
        dispatch(action());
      }, []);
    
      return (
        <Bar onClick={handler} value={value} />
      );
    };
    
    export default Foo;

    Вряд ли useStore вам, действительно, понадобится на практике.
    Ответ написан
    Комментировать
  • Как добавить значение в store redux?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Например
    import React, { useCallback, useRef } from 'react';
    import ReactDOM from 'react-dom';
    import { combineReducers, createStore } from 'redux';
    import { Provider, connect } from 'react-redux';
    
    // action type
    const ADD_MESSAGE = 'ADD_MESSAGE';
    
    // action creator
    const addMessage = payload => ({
      type: ADD_MESSAGE,
      payload,
    });
    
    // reducer
    const messages = (state = [], action) => {
      switch (action.type) {
        case ADD_MESSAGE:
          return [...state, action.payload];
        default:
          return state;
      }
    };
    
    // root reducer
    const rootReducer = combineReducers({
      messages,
    });
    
    // store
    const store = createStore(rootReducer);
    
    const App = ({ addMessage, messages }) => {
      const inputRef = useRef(null);
    
      const handler = useCallback(() => {
        addMessage(inputRef.current.value);
        inputRef.current.value = '';
      }, [inputRef, addMessage]);
    
      return (
        <div>
          <ul>
            {messages.map((message, i) => (
              <li key={i}>{message}</li>
            ))}
          </ul>
          <input ref={inputRef} />
          <button onClick={handler}>Add Message</button>
        </div>
      );
    };
    
    const mapStateToProps = state => ({
      messages: state.messages,
    });
    
    const mapDispatchToProps = {
      addMessage,
    };
    
    const ConnectedApp = connect(
      mapStateToProps,
      mapDispatchToProps
    )(App);
    
    const root = (
      <Provider store={store}>
        <ConnectedApp />
      </Provider>
    );
    
    const rootElement = document.getElementById('root');
    ReactDOM.render(root, rootElement);

    Пример с использованием redux-act
    import React, { useCallback, useRef } from 'react';
    import ReactDOM from 'react-dom';
    import { combineReducers, createStore } from 'redux';
    import { Provider, connect } from 'react-redux';
    import { createAction, createReducer } from 'redux-act';
    
    // action creator
    const addMessage = createAction('ADD_MESSAGE');
    
    // reducer
    const messages = createReducer({}, []);
    messages.on(addMessage, (state, message) => [...state, message]);
    
    // root reducer
    const rootReducer = combineReducers({
      messages,
    });
    
    // store
    const store = createStore(rootReducer);
    
    const App = ({ addMessage, messages }) => {
      const inputRef = useRef(null);
    
      const handler = useCallback(() => {
        addMessage(inputRef.current.value);
        inputRef.current.value = '';
      }, [inputRef, addMessage]);
    
      return (
        <div>
          <ul>
            {messages.map((message, i) => (
              <li key={i}>{message}</li>
            ))}
          </ul>
          <input ref={inputRef} />
          <button onClick={handler}>Add Message</button>
        </div>
      );
    };
    
    const mapStateToProps = state => ({
      messages: state.messages,
    });
    
    const mapDispatchToProps = {
      addMessage,
    };
    
    const ConnectedApp = connect(
      mapStateToProps,
      mapDispatchToProps,
    )(App);
    
    const root = (
      <Provider store={store}>
        <ConnectedApp />
      </Provider>
    );
    
    const rootElement = document.getElementById('root');
    ReactDOM.render(root, rootElement);
    Ответ написан
    Комментировать
  • Понимание жизненного цикла React вкупе с получением данных от сервера?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    В данном примере curPrice - это props получаемые от сервера

    Метод жизненного цикла componentDidMount вызывается после render.
    Ничего удивительного в том, что при первой отрисовке вместо данных вы получаете undefined нет. К этому моменту еще даже не инициирован ваш запрос на сервер.

    Поэтому чтобы записать State - приходится делать дополнительную проверку,
    которую я нигде в примерах не встречал - это правильно?..

    Тут не ясно для чего вам вообще использовать состояние. Если вы никак не изменяете это значение в своем компоненте, то используйте его напрямую из props.
    Ответ написан
  • Как менять состояние isFetching внутри одного редьюсера?

    rockon404
    @rockon404 Куратор тега React
    Frontend Developer
    Состояние коллекции пользователей лучше хранить в одном редьюсере.
    Если в приложение подразумевается работа с одной активной сущностью, то для нее лучше сделать отдельный редьюсер. В этом случае может быть удобным использовать один ключ для редактирования, сохранения и удаления.
    Если подобные ключи нужны для работы с коллекцией, например быстрое редактирование, добавление и удаление в таблице. То можно использовать коллекцию состояний:
    {
      isFetching: {
        'ALL': false,
        '122bc-e43gf-24002-12ea1-ca785': true,
      },
    }

    Где всегда есть свойство для всех сущностей и опционально добавляется для нужных элементов по id.
    Ответ написан
    Комментировать
  • Есть ли способ разделить действия и привязать их к определенным редьюсерам?

    rockon404
    @rockon404 Куратор тега Redux
    Frontend Developer
    Стандартной практикой является создать директорию actions и хранить действия в одноименных c редьюсерами файлах. Пример:
    5d338c9d40026982594687.png

    хотелось бы получить что-то подобное

    Какая-то ерунда. Смешали действия и combineReducers, какого эффекта при этом пытаетесь добиться непонятно.

    Советую использовать библиотеку redux-act. Сокращает бойлерплейт.
    Ответ написан
    Комментировать