LINUX.ORG.RU

React+Redux, быстро растет «бесполезный» код

 ,


0

2

Есть контейнер, который подключен к Redux'у. Этот контейнер, по сути, управляет всем приложением.

Метод в моем контейнере, который возвращает модальное окно «ModalPostSelect»:

createModalPostSelect(callbackOpen, callbackClose, callbackSelectPost, callbackPostExportStart, callbackLoadCheckLoop, posts) {
  const startExport = (postId) => {
    callbackSelectPost(postId);
    callbackPostExportStart();
    callbackLoadCheckLoop();
    callbackOpen(MODAL_EXPORT_PROGRESS);
  };
  return <ModalPostSelect
    callbackClose={callbackClose} 
    callbackPostSelect={startExport}
    posts={posts}
  />;
}
Обратите внимание на то, сколько у метода параметров. Уже здесь у меня закрадываются подозрения, что что-то идет не так... Слишком уж их много.

Часть метода render контейнера:

{ this.props.modals.current === MODAL_POST_SELECT && this.createModalPostSelect(
  this.props.actionModalOpen,
  this.props.actionModalClose,
  this.props.actionCommentsLoadSelectPost,
  this.props.actionCommentsLoadStart,
  this.props.actionCommentsLoadCheckLoop,
  this.props.commentsLoad.posts
) }

В чем, собственно, проблема - на сколько я понимаю, «правильно» передавать все необходимое для работы метода в качестве параметров, это облегчает тестирование, позволяет создавать чистые функции и т.д.

Но как быть, блин, с таким количеством бесполезного кода? Сначала передаем 6 параметров в метод, а потом еще и в самом методе тупо передаем данные/колбеки дальше. Бред же? Как упростить и сократить код, не растеряв при этом его качества?

Deleted

Welcome to Hell.

anonymous
()

Сначала передаем 6 параметров в метод, а потом еще и в самом методе тупо передаем данные/колбеки дальше.

Зачем передавать методу createModalPostSelect все эти параметры, если они уже в св-ах объекта?

neversleep ★★
()

Почему бы не передавать один объект, вместо кучи колбеков. В объекте храни че хочешь, те же методы (колбеки), либо ещё что поумнее, привязанное к shared state. Вообще, мне redux очень не нравится, в сравнении с vuex.

Не очень понятно, зачем возвращать компонент-модальное окно? Не проще сделать одно глобалное окно, настраивать его через стейт, и только затем показывать? И так каждый раз - хочешь показать новое содержимое в виде модального окна - вызывай сеттер стейта, показывай окно, скрывай окно.

menangen ★★★★★
()
Ответ на: комментарий от menangen

Почему бы не передавать один объект, вместо кучи колбеков.

Тогда еще как вариант можно объединить все коллбеки в один, а в параметрах передавать некий идентификатор характиризующий его, типа actionType.

neversleep ★★
()

Но как быть, блин, с таким количеством бесполезного кода?

Отличный пример, во что это потом превращается - Facebook. Глючит, тупит, тормозит и жрёт ресурсы.

th3m3 ★★★★★
()

Я мимокрокодил, но скажите, почему в этих ваших вебах не делают объекты со свойствами как в борланде было или в MFC? Или всё это говнище от асинхронности? Или от того, что жаваскриптеры не умеют в программирование, и, как писал выше menangen, можно (и нужно) писать нормально?

Shadow ★★★★★
()
Последнее исправление: Shadow (всего исправлений: 1)
Ответ на: комментарий от Shadow

Ну так напиши код так, как считаешь нужным. Об этом и тред, если ты не понял.

Deleted
()
Ответ на: комментарий от th3m3

родили в качестве костылей к тому что было, да

anonymous
()
Ответ на: комментарий от Shadow

объекты со свойствами это вчерашний день, не хочется руками туда сюда дергать всё это вручную, соответственно возникает либо непрозрачный двухсторонний биндинг либо лашпа типа реакта

anonymous
()

Метод в моем контейнере, который возвращает модальное окно «ModalPostSelect»

А почему этот контейнер не подключить к redux, чтоб он сам генерил события? Зачем ему экшены передаются из другого контейнера в виде колбеков?

Aber ★★★★★
()
Ответ на: комментарий от Shadow

Я мимокрокодил, но скажите, почему в этих ваших вебах не делают объекты со свойствами как в борланде было или в MFC?

Классы с методами? Я просто во времена MFC под стол ходил :) Ладно, на первом курсе был.... Но видел api vaadin, убер объекты с множеством методов на почти все случаи жизни. Почти. А вот когда нужно что-то поменять начинаются проблемы. Похоже на набор лего, пока устраивают квадратные дома и человечки - все в порядке.

Лично я в восторге от redux, наверное это пока не наткнулся на проблемы. React+redux делит приложение на три большие части:
1) Глобальная модель состояния приложения/веб-страницы (JSON)
2) Логика отрисовки UI по модели.
3) Бизнес-логика в виде редакса - функция которая создает копию состояния и затем «мутирует» её на основе входящего действия/события и предыдущего состояния.

Такую схему очень просто дебажить. Если ты сделал действия мышкой и ожидаешь изменнеия в UI а его нет, то смотришь модель (в json виде, можно форматированном), если изменения в модели нет, значит событие не ушло. Смотришь пришло ли событие в редакс функцию, если оно таки пришло, то в бизнес-логике ошибка. Если модель поменялась как нужно, то значит ошибка в отрисовки UI по модели.
UI рисовать легко, делаешь статичную модель со статично забитым состоянием, например отображение диалога с ошибкой в заголовке, пишешь отрисовку по модели, смотришь в браузере результат, меняешь в модели ошибку на успех, правишь UI, смотришь результат, теперь тестируешь в динамике, когда модель меняется уже от событий и бизнес логики.

Aber ★★★★★
()
Последнее исправление: Aber (всего исправлений: 1)
Ответ на: комментарий от Aber

Есть контейнер, который подключен к Redux'у. Этот контейнер, по сути, управляет всем приложением.

Он подключен к редаксу.

Deleted
()
Ответ на: комментарий от Deleted

Почему не подключены все нижестоящие контейнеры к редаксу, чтоб у каждого элемента был свой mapStateToProps? Похоже у тебя топовый контейнер выполняет роль толи контроллера, толи медиатора. Я не понял из фрагмента кода архитектуру приложения.

Aber ★★★★★
()
Ответ на: комментарий от Aber

Почему не подключены все нижестоящие контейнеры к редаксу

По тому, что это не контейнеры. Я четко разделаю все «компоненты приложения» на контейнеры (это то, что подключено к редаксу) и презентеры (это то, что просто «рисует» страницу и изменяет стор посредством колбеков от контейнера).

Почему-то многие думают, что подключать редакс везде и всюду - это хорошо. Это не хорошо, по тому, что React !== Redux. Редакс это хранилище, чем меньше мы зависим от хранилища, тем лучше. В конце-концов, в какой-то момент мы можем банально захотеть сменить редакс на другое хранилище.

Мой текущий код код, когда только контейнеры подключены к хранилищу, легко позволяет это сделать. Если подключать все компоненты к хранилищу - будет ад. Но он не без минусов, вот я и пытаюсь разобраться, как его улучшить.

Deleted
()
Последнее исправление: Bizun (всего исправлений: 1)
Ответ на: комментарий от Deleted

Это не хорошо, по тому, что React !== Redux. Редакс это хранилище, чем меньше мы зависим от хранилища, тем лучше. В конце-концов, в какой-то момент мы можем банально захотеть сменить редакс на другое хранилище.

В мое случае текущее приложении сразу строилось на redux и только потом самописный виртуальный dom был заменен на react. Так что мое приложение получилось redux ориентированное. Ад пока не предвижу, но приложение пока еще не очень большое. Свой воркфлоу работы с кодом я написал комментом выше в ответе Shadow'у.

Aber ★★★★★
()
Последнее исправление: Aber (всего исправлений: 1)

Тут в реакт добавили Context: https://habrahabr.ru/company/ruvds/blog/348862/

Я вот думаю, что в моем случае его можно заюзать для модальных окон, вот так:

const ModalsContext = createContext({
    modalOpen: ... ,
    modalClose: ... ,
    modalForceClose: ...
})

...

return <ModalsContext.Provider>
  <Modal1/>
  <Modal2/>
  <Modal3/>
</ModalsContext.Provider>

Это же, по идее, правиьный use-case?

Deleted
()
Ответ на: комментарий от Aber

Свой воркфлоу работы с кодом я написал комментом выше в ответе Shadow'у

Я ни чего не написал про твой воркфлоу, по тому, что я пишу, по сути, так же.

Но меня настораживает то, что ты подключаешь все компоненты к редаксу и кговоришь, что дебажить - легко.

Моя практика показывает, что в таком случае, дебажить не легко =(

Deleted
()
Ответ на: комментарий от Deleted

А мне кажется что не легко распространять модель вниз по иерархии объектов, все становится громоздким. Подключая redux ко всем хоть сколько сложным компонентам (диалог, панель, форма с таблицей) я избавляюсь от иерархий и биндиг модели на UI упрощается.

Я пока кодю на ract+redux несколько месяцев, так что не эксперт, но как только увижу проблемы придется искать новое решение или подход. Может еще и поменяю точку зрения на противоположную, но пока доволен.

Aber ★★★★★
()
Последнее исправление: Aber (всего исправлений: 1)

Кстати немного оффтоп, но. Я вот заметил во всяких легаси есть код который НИКОГДА не используется (раньше использовался). Для каких языков есть тулза типа профайлера которую запустил. Юзеры 2 месяца работают, а ты потом смотришь какой код не использовался НИ разу.

demrnd
()
Ответ на: комментарий от Aber

Погляди на VUE.js Меня вообще Реакт напугал тем звездецом что в нем......

demrnd
()
Ответ на: комментарий от Shadow

Море коллбеков не всегда возникает, тут как приготовишь.

а ручное копирование состояния между view и model это портянки тупого однотипного кода почти наверняка

anonymous
()
Ответ на: комментарий от Shadow

почему в этих ваших вебах не делают объекты со свойствами как в борланде было или в MFC?

Делают. В angular, vue и чистом react так и есть. В случае с react/redux подразумевается, что компоненты — это stateless view, они только рендерят готовые данные.

static_lab ★★★★★
()
Последнее исправление: static_lab (всего исправлений: 1)
Ответ на: комментарий от Deleted

Тут в реакт добавили Context

У тебя уже есть redux, он сам работает через контексты.

И вообще, тебе нужно было просто сделать так:

{ this.props.modals.current === MODAL_POST_SELECT && (
    <ModalPostSelect
        callbackClose={this.props.actionModalClose} 
        callbackPostSelect={this.props.startExport}
        posts={this.props.commentsLoad.posts}
    />
) }

А уже в action creator вызовешь все нужные действия.

static_lab ★★★★★
()
Последнее исправление: static_lab (всего исправлений: 1)
Ответ на: комментарий от static_lab

И вообще, тебе нужно было просто сделать так

Лол, я пару минут назад практически так и сделал:

{this.props.modals.current === MODAL_POST_SELECT && (
  <ModalPostSelect
    callbackClose={this.props.actionModalClose} 
    callbackPostSelect={(postId) => {
      this.props.actionCommentsLoadSelectPost(postId);
      this.props.actionCommentsLoadStart();
      this.props.actionCommentsLoadCheckLoop();
      this.props.actionModalOpen(MODAL_EXPORT_PROGRESS);
    }}
    posts={this.props.commentsLoad.posts}
  />
)}

Только, как видишь, колбек я передаю явно, без «action creator».

И сори за тупой вопрос, но все же, «action creator» - это вот это?

function mapDispatchToProps(dispatch, ownProps) {
  return {
    // Accounts
    actionAccountsLoad: () => {
      dispatch(accountsLoad());
    },
    // Comments Load
    actionCommentsLoadSelectAccount: (id) => {
      dispatch(commentsLoadSelectAccount(id));
    },
    actionCommentsLoadPosts: () => {
      dispatch(commentsLoadPosts());
    },
    actionCommentsLoadSelectPost: (id) => {
      dispatch(commentsLoadSelectPost(id));
    },
    actionCommentsLoadStart: () => {
      dispatch(commentsLoadStart());
    },
    actionCommentsLoadCheckLoop: () => {
      dispatch(commentsLoadCheckLoop());
    }
  };
}

Или «action creator» - это, собственно, код, который описывает экшен? Типа такого:

export const commentsLoadStart = () => {
  return async (dispatch, getState) => {
    try {
      const state = getState();
      const accountId = state.commentsLoad.selectedAccountId;
      const postId = state.commentsLoad.selectedPostId;
      const data = await LiveDuneApi.post('reactComments/export', { accountId, postId });
      if (data && data.export_id !== undefined && data.export_id) {
        dispatch({ type: CL_SET_EXPORT_ID, payload: data.export_id });
      } else {
        dispatch({ type: CL_SET_EXPORT_STATUS, payload: STATUS_ERROR });
      }
    } catch (error) {
      console.log(error);
      dispatch({ type: CL_SET_EXPORT_STATUS, payload: STATUS_ERROR });
    }
  }
};

Просто я не очень понимаю, где ты предлагаешь «описать колбек», говоря:

А уже в action creator вызовешь все нужные действия.

Deleted
()
Ответ на: комментарий от Deleted

Только, как видишь, колбек я передаю явно, без «action creator».

Это не очень хорошо, потому что у тебя функция будет заново создаваться в каждом цикле рендеринга.

«action creator» - это, собственно, код, который описывает экшен

Action creator — это по определению функция, которая создаёт объект экшена. То есть да, второе.

static_lab ★★★★★
()
Ответ на: комментарий от static_lab

Action creator — это по определению функция, которая создаёт объект экшена. То есть да, второе.

Ага, понял. Хочу еще кое-что обсудить. Глянь на вот этот код еще раз:

...
callbackPostSelect={(postId) => {
  this.props.actionCommentsLoadSelectPost(postId);
  this.props.actionCommentsLoadStart();
  this.props.actionCommentsLoadCheckLoop();
  this.props.actionModalOpen(MODAL_EXPORT_PROGRESS);
}}
...
Обрати внимание на имена функций. Есть actionCommentsLoad* и actionModal*.

К чему это я - используются экшены из разных reducer'ов. Каким, в таком случае, должен быть «action creator»?

На сколько я понимаю, использовать экшены редьюсера CommentsLoad в редьюсере Modal это же не очень хорошо.

Хз, может есть какой-то паттерн на этот случай, или еще чего?

Deleted
()
Последнее исправление: Bizun (всего исправлений: 1)
Ответ на: комментарий от static_lab

Если я правильно тебя понял, то создаем action-type «ACTION_COMMENTS_LOAD_POST_SELECT», далее, в редьюсере Modals:

case ACTION_COMMENTS_LOAD_POST_SELECT: {
  const stack = state.stack.push(MODAL_EXPORT_PROGRESS);
  return { ...state, current: MODAL_EXPORT_PROGRESS, stack };
}

И в редьюсере CommentsLoad:

case ACTION_COMMENTS_LOAD_POST_SELECT: {
  // ???
}

Вот здесь вылазят проблемы, т.к. для того, чтобы сделать:

this.props.actionCommentsLoadSelectPost(postId);
this.props.actionCommentsLoadStart();
this.props.actionCommentsLoadCheckLoop();

Выполняется вот это:

export const commentsLoadSelectPost = (id) => {
  return (dispatch, getState) => {
    const state = getState();
    const selectedPost = state.commentsLoad.posts.find(post => post.id === id);
    const payload = {
      postId: id,
      totalComments: selectedPost.comments
    };
    dispatch({ type: CL_SELECT_POST, payload });
  }
}

export const commentsLoadStart = () => {
  return async (dispatch, getState) => {
    try {
      const state = getState();
      const accountId = state.commentsLoad.selectedAccountId;
      const postId = state.commentsLoad.selectedPostId;
      const data = await LiveDuneApi.post('reactComments/export', { accountId, postId });
      if (data && data.export_id !== undefined && data.export_id) {
        dispatch({ type: CL_SET_EXPORT_ID, payload: data.export_id });
      } else {
        dispatch({ type: CL_SET_EXPORT_STATUS, payload: STATUS_ERROR });
      }
    } catch (error) {
      console.log(error);
      dispatch({ type: CL_SET_EXPORT_STATUS, payload: STATUS_ERROR });
    }
  }
};

export const commentsLoadCheckLoop = () => {
  return async (dispatch, getState) => {
    const checkFunction = async () => {
      try {
        const state = getState();
        const exportId = state.commentsLoad.exportId;
        if (exportId !== null) {
          const data = await LiveDuneApi.get('reactComments/exportStatus', { exportId });
          if (data.loaded !== undefined && data.loaded) {
            dispatch({ type: CL_SET_EXPORT_LOADED, payload: data.loaded });
          }
          if (data.link !== undefined && data.link) {
            dispatch({ type: CL_SET_EXPORT_LINK, payload: data.link });
            return;
          }
        }
        setTimeout(() => checkFunction(), 1000);
      } catch (error) {
        console.log(error);
        dispatch({ type: CL_SET_EXPORT_STATUS, payload: STATUS_ERROR });
      }
    };
    checkFunction();
  }
};

Как такое запихнуть в редьюсер? Не диспатчить же экшены из редьюсера...

Deleted
()

Переходи на Vue.js. Он сделан для людей!

anonymous
()
Ответ на: комментарий от Aber

1) Глобальная модель состояния приложения/веб-страницы (JSON)

Которая противоречит ФП и чистоте как таковой. Но это даже не самое важное - зачем тебе нужно глобальное состояние? Что оно тебе даёт? Ты ведь не написал.

2) Логика отрисовки UI по модели.

Чё?

3) Бизнес-логика в виде редакса - функция которая создает копию состояния и затем «мутирует» её на основе входящего действия/события и предыдущего состояния.

Чё? Любая логика изменяющая состояние - его изменяет. Это её основное свойство. Причём тут эти базворды?

Такую схему очень просто дебажить. Если ты сделал действия мышкой и ожидаешь изменнеия в UI а его нет, то смотришь модель (в json виде, можно форматированном)

Удачи посмотреть в «модель» не хелворда. Опять же, любое состояние на то и состояние, что его можно посмотреть. Что тебе мешает посмотреть его без этой поделки?

если изменения в модели нет, значит событие не ушло. Смотришь пришло ли событие в редакс функцию, если оно таки пришло, то в бизнес-логике ошибка.

И, что это даёт?

Если модель поменялась как нужно, то значит ошибка в отрисовки UI по модели.

Ахренеть, колхозники не осилил трейс? Кстати, к чему ты вообще это пишешь? Ведь это ничего не даёт, ведь локализация подобного уровня ничего не стоит.

vcerloman
()
Ответ на: комментарий от vcerloman

Которая противоречит ФП и чистоте как таковой.

И где я сказал про ФП? Надеюсь все функциональщики обходятся без БД, а то ведь сторадж состояний, ужас-ужас.

зачем тебе нужно глобальное состояние?

Вот для

Опять же, любое состояние на то и состояние, что его можно посмотреть.

Взять любое нетривиальное приложение, там этих состояний миллион и все в разных местах, классическое ООП этому способствует, миллион объектов - миллион состояний. Потому дебаггинг начинается с воспроизведения последовательности шагов, для того, чтоб привести приложение к нужному состоянию, затем нужно просмотреть состояния множества объектов, а после проанализировать последовательность операций над объектами которые привели к конечному состоянию. Это съедает очень много времени, например я трачу от 20 минут на дебагинг spring для нахождения способа меняющего поведение стандартных компонентов.

Чудо редукса:

1) Исходные данные: есть огромное глобальное состояние и непонятки работы после модификаций кода. Печатается форматированный json состояния рабочего кода и не очень рабочего, два json сравниваются в meld, нет более очевидной разницы состояний.

2) Модифицируется код отображения или бизнес-логики, после модификаций приложение перезагружается но нет необходимости в steps to reproduce, девелопмент плагин в браузере восстанавливает сохраненное ранее состояние, например, сразу отображается диалог визарда на 10-ом шаге, с котором были проблемы.

Aber ★★★★★
()
Ответ на: комментарий от static_lab

В общем, я долго думал как лучше, в итоге сделал так:

{this.props.modals.current === MODAL_ACCOUNT_SELECT && (
  <ModalAccountSelect 
    callbackClose={this.props.actionModalClose} 
    callbackAccountSelect={this.props.actionCommentsLoadAccountSelect}
    accounts={this.props.accounts.social}
  />
)}
{this.props.modals.current === MODAL_POST_SELECT && (
  <ModalPostSelect
    callbackClose={this.props.actionModalClose} 
    callbackPostSelect={this.props.actionPostSelect}
    posts={this.props.commentsLoad.posts}
  />
)}

function mapDispatchToProps(dispatch, ownProps) {
  return {
    ...
    actionCommentsLoadAccountSelect: (accountId) => {
      dispatch(commentsLoadSelectAccount(accountId));
      dispatch(commentsLoadPosts());
      dispatch(modalOpen(MODAL_POST_SELECT));
    },
    actionPostSelect: (postId) => {
      dispatch(commentsLoadSelectPost(postId));
      dispatch(commentsLoadStart());
      dispatch(modalOpen(MODAL_EXPORT_PROGRESS));
    },
    ...
  };

Да, наверное, здесь не очень правильно описывать «action creator». Но проблема в том, что у меня нет action creator'ов как отдельной сущности, т.к. я юзаю Duck-контейнеры. У меня в одном файле константы экшенов, экшены и редьюсер. Это выглядит вот так:

// Constants
import {
  STATUS_OK,
  STATUS_LOADING,
  STATUS_ERROR
} from '../constants';

import LiveDuneApi from '../utils/LiveDuneApi';

// Actions
const USER_SET_ID     = "ld-comments/user/USER_SET_ID";
const USER_SET_STATUS = "ld-comments/user/USER_SET_STATUS";

export const userLoad = () => {
  return async (dispatch) => {
    try {
      const data = await LiveDuneApi.get('reactComments/userData');
      dispatch({ type: USER_SET_ID, payload: data.user_id || [] });
      dispatch({ type: USER_SET_STATUS, payload: STATUS_OK });
    } catch (error) {
      console.log(error);
      dispatch({ type: USER_SET_STATUS, payload: STATUS_ERROR });
    }
  };
};

const initialState = {
  status: STATUS_LOADING,
  id: null,
};

export default (state = initialState, action) => {
  switch (action.type) {
    case USER_SET_ID: {
      return { ...state, id: action.payload };
    }
    case USER_SET_STATUS: {
      return { ...state, status: action.payload };
    }
    default:
      return state;
  }
};

Мне не нравится классический вариант организации проекта с Redux, т.к. получается слишком много разрозненных частей, по этому, собственно, я и юзаю Duck-контейнеры.

Что скажешь?

Deleted
()
Ответ на: комментарий от Aber

И где я сказал про ФП? Надеюсь все функциональщики обходятся без БД, а то ведь сторадж состояний, ужас-ужас.

Не ты сказал, а эксперты, которые родили этот ужас. Вернее как - ты то же сказал, вернее твоя лексика за тебя сказала. «мутирует» и прочая ахинея - это ФП-лексика.

Взять любое нетривиальное приложение, там этих состояний миллион и все в разных местах, классическое ООП этому способствует, миллион объектов - миллион состояний. Потому дебаггинг начинается с воспроизведения последовательности шагов, для того, чтоб привести приложение к нужному состоянию, затем нужно просмотреть состояния множества объектов, а после проанализировать последовательность операций над объектами которые привели к конечному состоянию. Это съедает очень много времени, например я трачу от 20 минут на дебагинг spring для нахождения способа меняющего поведение стандартных компонентов.

Это не работает, ты подменяешь понятия. Кто тебе запрещает использовать одно единственное состояние? Используй. Причём тут эта поделка?

А далее, ты так же манипулируешь. Никаким образом одно состояние тебе не позволит локализовать проблему. Ты будешь её локализовывать руками. При этом, причём тут это поделие - решительно неясно.

Где именно и что меняется - ты узнаешь итак. Кнопка связана с каким-то объектом, а этот объект ты можешь потрейсить. При этом - ты будешь это делать в любом случае.

1) Исходные данные: есть огромное глобальное состояние и непонятки работы после модификаций кода. Печатается форматированный json состояния рабочего кода и не очень рабочего, два json сравниваются в meld, нет более очевидной разницы состояний.

Из этого ничего не следует. Ты не учитываешь цену применения этой поделки, которую автор уже продемонстрировал. Ты реализуешь данный функционал, а не поделка. Ты опять всё перепутал.

2) Модифицируется код отображения или бизнес-логики, после модификаций приложение перезагружается но нет необходимости в steps to reproduce, девелопмент плагин в браузере восстанавливает сохраненное ранее состояние, например, сразу отображается диалог визарда на 10-ом шаге, с котором были проблемы.

Это так же имеет никакого отношения к поделки. Ты не учёл цену применения поделки, а так же то, что это работает только для хелвордов.

Давай попроще. Вот я пишу этот коммент - ты будешь на каждый ввод символа создавать состояние? Нет. А если будешь - это будет полная жопа. Можешь ли ты восстановить состояние? Нет.

Если ты локализовал проблему, то тебе не нужно заниматься хернёй и воспроизводить её в контексте. Ты уже понял, как контекст на неё влияет, если он влияет.

И имея некий объект, который можно протестировать отдельно - тебе не нужно заниматься подъёмом какого-то неведомого глобального состояния, который нехрен не нужен, который стоит сотен строк бойлерплейта на каждый чих, да и который не работает.

Если у тебя некий диалог триггерит какое-то событие, то в логе у тебя будет только это событие. Ты не сможешь триггернуть его из состояния. Ведь промежуточные состояние у тебя не сохраняются, да и сам триггер без не вызовется.

Ведь у тебя логика - есть отклик на событие, которое запись нового глобального состояния - не триггерит. Это фундаментальная проблема, и судя потому, что ты её не понимаешь - это очень плохо.

Состояние гуйни нахрен никому не нужно. Это капля в море. Всем нужна логика, которую состояние никак не триггерит.

vcerloman
()
Ответ на: комментарий от Deleted

Знаешь почему у тебя есть одна точка входа в изменение состояния? Тебе кажется, что это круто/модно - нет. Просто колхозники не осилил реализовать иначе. В рамках колхоза нельзя реагировать на изменение полей.

В конечном итоге, любой вменяемый человек пытается костылить себе нормальное ООП, а не этот мусор. Ты уже накастылил себе методы, уже накастылили себе отдельное состояние для USER.

Ничего, скоро ты поймёшь, что нет смысла делать метод, который вызывает мусор, который вызывает реальный метод через ещё 2 слоя мусора. Проще сделать метод, который и будет делать то, что нужно.

Вся проблема заключается в том, как соединить данные и с гуйнёй. Для этого есть нормальные средства, в частности мобх.

Я, конечно, не эксперт в том, как вам там надо ваять. Но когда я пытался найти хоть какой-то готовый и вменяемый стек под вебчик - я чуть не проблевался с этой поделки, накастылил себе кастылей, а потом оказалось, что пацаны уже всё сделали, пусть и не идеально, но вменяемо. И называется это мобх.

vcerloman
()
Ответ на: комментарий от vcerloman

Это не работает, ты подменяешь понятия. Кто тебе запрещает использовать одно единственное состояние? Используй. Причём тут эта поделка?

На всякий случай я напомню, что react+redux это не фрейморк это библиотека. Redux фактически подход. Для меня это еще одна вариация MVC уровня приложения.

Все это слишком дискуссионно, помню работал над один проектом, простыми словами его можно описать как CRUD со сложными бизнес правилами и таск треккер в одном лице, корпоративные пользователи вносили правки в общую БД, с оптимистичной блокировкой(с известными ограничениями), когда-то вдруг появилась идея сериализовывать их работу в xml и умно применять против БД, что-то там не срослась с применением к БД, но последовательности изменений записывалась. Эту логику никто не выпиливал, это был хоть и муторный но довольно действенный способ узнать последовательность операций над данными которые пытался совершить пользователь. Redux рекламирует что-то вроде этого, я пока к этому не пришел, но теоретически redux позволить воссоздать состояние любого пользователя, хоть онлайн шарить их работу, взял модель и получать все операции(action's) над ней в реальном времени, наверное так это должно работать, пока не вникал. Потому я считаю react+redux очень классной идеей.

Aber ★★★★★
()
Ответ на: комментарий от Aber

На всякий случай я напомню, что react+redux это не фрейморк это библиотека.

Ки.

Redux фактически подход.

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

За примерами далеко ходить не надо. Даже самые ярые адепты это поделки, всё равно рано или поздно приходят к разделению состояний, как и к реализации методов, вместо передачи аргументов в убогую функцию. Т.е. даже самые ярые защитники подтираются этими «идеями» - ведь они попросту несостоятельны.

Для меня это еще одна вариация MVC уровня приложения.

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

Redux рекламирует что-то вроде этого, я пока к этому не пришел

И не придёшь, потому что эта ахинея невероятная. К этому нельзя прийти, это нельзя понять - в это можно только верить.

Как верить в какую-то иммутабельность, ФП и прочую ахинею. Зачем это нужно - никто понять не может. Почему-то все пытаются всякие foreach() записать в ФП, хотя это нихрена не ФП. А больше ничего полезного и не вспомнишь.

но теоретически redux позволить воссоздать состояние любого пользователя, хоть онлайн шарить их работу, взял модель и получать все операции(action's) над ней в реальном времени, наверное так это должно работать, пока не вникал.

Не позволяет. Я уже тебе определил фундаментальную проблему. Ты не можешь состоянием воспроизвести все произошедшие над состоянием операции.

Ты можешь только записать лог и воспроизвести его, но то же самое ты можешь с делать и без этой поделки. Опять же - как ты получишь лог во время ошибки? Никак - ты можешь получить только состояние.

В этом и заключается фишка. Жонглируя этими понятиями - тебя обманывают. Тебе говорят про стейт и про фишки, но на самом деле этого ничего не даёт. Ведь тебе кажется, что раз я могу нарисовать состояние, то оно будет рисоваться так же, как они рисуется в реальности - нет. Не так же. Ты выкидываешь вообще исполнение какой-либо логики.

Потому я считаю react+redux очень классной идеей.

Потому, что не понимаешь? Очень хорошо. Правда вот, почему оно классное - ты так и не написал. И зачем записываешь это через плюсик? Ты подсознательн понимаешь, что эта поделка ничего не стоит и к ней надо приписать react, чтобы она хоть что-то стоила? Не надо так.

Данный контекст вообще никакого отношения к реакту не имеет. Это лишь гуйня.

На самом деле - ты просто наделяешь эту поделку левыми свойствами. Её свойствами является только то, что уникально ей, т.е. её свойства, а не свойство подхода в целом.

Эта поделка обладает несколькими уникальными свойствами, а именно - ущербанским интерфейсом. Это признают все, в частности - ТС.

Ущербанским загоном состояний всех объектов в одно. Это признают все, в частности - ТС. Уже давно адепты разделяют состояния, а потом их объединяют. Именно так и должно быть, но данная поделка это не осилила.

Ущербанской реализацией, а именно шизофренией поверх иммутабельности. Именно из-за этого колхозникам и пришлось объединять состояние в одно. Ведь ты не можешь без полного контекста обновить всё состояние.

Реализация прикастыливания этой поделки к реакту - верх идиотизма. Такого дерьма я давно не видел, вернее никогда не видел. Это так же признают все, включая ТС"а.

Т.е. данная поделка - есть чистейший мусор, и это признают все. Создана тысячи кастылей для обхода этих ущербностей, но адепты всё никак не могут признать факт - поделка убога.

Хотят - пусть упарываются. Это их право.

vcerloman
()
Ответ на: комментарий от Deleted

Но проблема в том, что у меня нет action creator'ов как отдельной сущности, т.к. я юзаю Duck-контейнеры.

Это неправда. Action creator по определению — это функция, возвращающая экшен (а экшен — это, кстати, объект с полями type и payload). Такими функциями у тебя является, в частности, userLoad. Так что в свой duck-контейнер нужно и тянуть actionCommentsLoadAccountSelect и actionPostSelect. Прочитай уже, что ли, документацию к Redux.

static_lab ★★★★★
()
Ответ на: комментарий от vcerloman

Ведь тебе кажется, что раз я могу нарисовать состояние, то оно будет рисоваться так же, как они рисуется в реальности - нет. Не так же. Ты выкидываешь вообще исполнение какой-либо логики.

Стоп, но ведь ради этого создан требование к redux функциям быть чистыми, т.е. не использовать данные за пределами переданных состояния + действия. Оба могут быть записаны и воссозданы.

Ущербанским загоном состояний всех объектов в одно.

В чем его ущербность? Если у нас одно хранилище состояний, есть четкие границы между источниками событий и хранилищем, то мы можем перехватывать и записывать все действия в одном месте. Можно к хранилищу относиться как к БД.

Ты можешь только записать лог и воспроизвести его, но то же самое ты можешь с делать и без этой поделки.

Я тебе и привел пример когда такой лог писался в xml. Это было нетривиально, логика делалась для другого. Много ли ты видел что сериализовывался граф доменных объектов для логирования действий? А с redux это можно из почти коробки получить.

Хотят - пусть упарываются. Это их право.

Не страдаю карго культом, как только не устроит найду другое решение. Четкий кейс где я напарюсь на неприятности ты мне не привел.

Aber ★★★★★
()
Последнее исправление: Aber (всего исправлений: 2)
Ответ на: комментарий от Aber

Стоп, но ведь ради этого создан требование к redux функциям быть чистыми, т.е. не использовать данные за пределами переданных состояния + действия. Оба могут быть записаны и воссозданы.

Неверно. Ты уже мне отвечал «а причём тут ФП?», а теперь оказывается выяснил - причём тут оно. Это хорошо. Давай продолжим.

Нет, все рассуждения о чистоте - есть манипуляции и враньё. Эта поделка сама по себе не чистая, ведь чистота не предполагает побочных эффектов, а вся твоя логика - есть побочные эффекты.

Давай попроще. Возьмём примитивную логику. click() -> sotore = process(load(«my_super_url»)); Что ты тут видишь? Ты видишь, что на нажатие кнопки у тебя происходит ПОБОЧНЫЙ ЭФФЕКТ( он не чистый. Вообще, на будущие, тебе нужно понять, что концепция ФП в целом, как и чистоты в частности - есть мусорный мусор, который не состоятелен совсем, вернее это каноничный пример несостоятельности, ведь весь мир состоит из побочных эффектов).

Далее, ты получаешь данные, которые после обрабатываешь. Они идут в твоё хранилище. Ты не можешь, воссоздать это. Ты можешь воссоздать это, воссоздав событие, которое затригеррил клик, но - это совершенно другое, нежели сохранение/востановление состояния.

Далее, т.к. логика, которую вызывает событие не чиста - ты попросту не можешь её воспроизвести. Ты должен будешь эмулировать сохранение возврата, т.е. того, что вообще противоречит ФП.

Давай попроще. Если если есть c(b(a)), где c/b - чистые функции, то там не нужно сохранять возврат b() - нам нужно сохранить только a.

На самом деле это никто не делает, и хранит в состоянии уже готовые данные, а не промежуточные.

В чем его ущербность? Если у нас одно хранилище состояний, есть четкие границы между источниками событий и хранилищем, то мы можем перехватывать и записывать все действия в одном месте. Можно к хранилищу относиться как к БД.

Неверно. Я ведь всё объяснил.

Ты вообще пытался представить себе БД с такой мусорной архитектурой? Где на каждый запрос тебе отправляется вся БД и ты там сам что-то ищешь? Ты явно не понимаешь, что говоришь.

БД на то и БД, что это ОБЪЕДИНЕНИЕ ОТДЕЛЬНЫХ ОБЪЕКТОВ. Будь то таблицы, объекты или ещё какая херня.

А вот мусорная поделка - это именно одна таблица, один объект. Изначально один - это полное убожество. И как я тебе говорил - это признанно всеми.

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

Почему, давай я тебе объясню. Вот у меня есть мой pwd. В котором я каталожики и работают. Внимание вопрос, почему я имею этот самый pwd-контекст, почему я использую относительные пути? Правильно, потому что это удобно.

Я не использую глобальные пути, ведь я не идиот. А что ты делаешь в своей поделке? Ты глобально хардкоришь каждый путь к каждому фалу глобально.

Я тебе и привел пример когда такой лог писался в xml. Это было нетривиально, логика делалась для другого. Много ли ты видел что сериализовывался граф доменных объектов для логирования действий? А с redux это можно из почти коробки получить.

Неможно, ты подменяешь понятия и пишешь не совсем вмеянемые вещи.

Этот колхоз - это просто трейс вызова функции. И смысл этой поделки в том, что ты все обращения делаешь через эту функцию.

Тебе нужно лишь переопределить/написать аналог fun.call(), вставив в него трейс и все функции сделать свободными, а далее вызвать необходимые функции через этот call(). Будет точно такой же трейс, только намного проще.

Ведь тебе не нужно будет конвертировать функцию в колхоз-строку, потом свичём конвертировать её опять в тело, как это делается в этой убогой поделке.

function user_set_status(status) {}
function user_set_id(id) {}


function call(fptr) {
  let args = [...arguments];
  args.shift();
  let res = fptr(args);
  console.log(`${fptr.name}(${args}) -> ${res} `);
}

const userLoad = async () => {
  try {
    const data = await LiveDuneApi.get('reactComments/userData');
    call(user_set_id, data.user_id || []);
    call(user_set_status, STATUS_OK);
  } catch (error) {
    console.log(error);
    call(user_set_status, STATUS_ERROR);
  }
};

Вот и вся твоя «сложность» с трейсом. Пойми, что сложно - это когда удобно, а тот мусор сделать не для того, чтобы тебе удобно было - он сделать так лишь потому, что это самое примитивное и убогое решение, то - которое любой колхозник может релизовать.

При этом, воспроизвести это можно точно ток же. Наверное колхозники об этом не знаю, но функции/методы не нужно преобразовывать в строки - это жс. Они итак строки, и по имени любую функцию итак можно вызвать.

Не страдаю карго культом, как только не устроит найду другое решение.

Не найдёшь. Ты пытаешься рассказать мне о том, что оно круто. А как только дело доходит до «почему» - ты отвечешь, - «я не знаю».

Четкий кейс где я напарюсь на неприятности ты мне не привел.

Кейсы тебе привёл уже автор, да и я уже привёл их множество. Ущербанская архитектура, ущербанский апи, который может использовать только фанатик, ведь это просто невозможно использовать в здравом уме.

Хотя, если вам там платят за генерацию лапши ненужной, то смысл нарисовывается, а так.

vcerloman
()
Ответ на: комментарий от anonymous

Там не с чем знакомиться. Да и уже вроде как достаточно давно познакомился. Неделю назад.

vcerloman
()
Ответ на: комментарий от vcerloman

там нужно ...args, а не args. Только щас увидел. Но в любом случае - понятно, что именно я имел ввиду.

vcerloman
()
Ответ на: комментарий от vcerloman

Далее, ты получаешь данные, которые после обрабатываешь. Они идут в твоё хранилище. Ты не можешь, воссоздать это. Ты можешь воссоздать это, воссоздав событие, которое затригеррил клик, но - это совершенно другое, нежели сохранение/востановление состояния.

В силу того, что асинхронный запрос возвращает состояние внешнего источника данных, то как бы да, но асинхронные запросы обычно выполняются к собственному серверу, у нас есть представления о состоянии сервера и данных хранящихся в нем. Проблема обычно на клиенте, что там творится непонятно.

Тебе нужно лишь переопределить/написать аналог fun.call(), вставив в него трейс

Ок, этого было бы достаточно для дебага. Но эта ниформация недоступна для инструментальной обработки, с redux можно снифить события у пользователя и воспроизводить действия, скажем для аналитики исползования UI.

Где на каждый запрос тебе отправляется вся БД и ты там сам что-то ищешь?

const mapStateToProps = (state, ownProps) => {
    const userId = state.panels.UserEditor.userId;
    return {
        user: state.data.users[userId], 
    }
}

Не вижу большой разницы со слоем работы с бд в котором есть запрос select * from users where id = ?

Aber ★★★★★
()
Ответ на: комментарий от vcerloman

Вся проблема заключается в том, как соединить данные и с гуйнёй. Для этого есть нормальные средства, в частности мобх.

Я посмотрю mobx. Я сам к react пришел только потому, что мне нужен был биндинг данных к dom, вначале попробовал knockoutjs потом react, но с чистым react без redux получилось как у ТС и даже хуже.

Aber ★★★★★
()
Ответ на: комментарий от Aber

В силу того, что асинхронный запрос возвращает состояние внешнего источника данных, то как бы да, но асинхронные запросы обычно выполняются к собственному серверу, у нас есть представления о состоянии сервера и данных хранящихся в нем. Проблема обычно на клиенте, что там творится непонятно.

Т.е. реальность рушиться? Это хорошо. А как всё начиналось хорошо. Сохранить/восстановить состояние, а потом оказалось, что надо сохранять весь лог событий. Теперь же оказалось, что мало того, что надо сохранять лог событий - надо сохранять лог ответов на сервере, при этом их ещё как-то синхронировать.

И ты не забывай, что я ещё не начал говорить о том - как же восстановить это состояние из лога. Ведь агитка предполагает только запись состояния, которое ничего( на самом деле) не даёт.

Ок, этого было бы достаточно для дебага.

Это функционально-полный аналог того колхоза, что даёт эта поделка. Может только в чуть упрощённой форме.

Но эта ниформация недоступна для инструментальной обработки, действия, скажем для аналитики исползования UI.

Ничего не понял. Ты пытаешься выдать колхоз-гуйню для хрома за фичу этой поделки? Это некстлевел.

с redux можно снифить события у пользователя и воспроизводить

Как и здесь, как и здесь.

Не вижу большой разницы со слоем работы с бд в котором есть запрос select * from users where id = ?

И это плохо, ведь колбаса растёт на деревьях. Удачи передавать state на 1тб в каждом запросе.

Кстати, а откуда ты взял пути? Неужели, если мне понадобиться панель засунуть куда-то, то у меня всё сломается?

Странные вы люди, конечно.

vcerloman
()
Ответ на: комментарий от Aber

но с чистым react без redux получилось как у ТС и даже хуже.

У ТС все проблемы - это именно то, как выглядит эта поделка. То дерьмо, что рождают люди при использовании данной поделки - худшее, что я когда-либо в вебчике видел. Конечно, я мало что в вебчике видел, но всё же.

vcerloman
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.