Каков наилучший практический подход для превращения данных из хранилища избыточных данных в простую функцию? - PullRequest
0 голосов
/ 01 ноября 2018

Скажем, у меня есть функция с именем calculateFees, для которой нужны некоторые данные, отправленные из бэкэнда, например consultingFee. Это будет выглядеть примерно так:

const calculateFees = itemPrice => itemPrice * [consultingFee]

[consultingFee] - это заполнитель, так как я не уверен, как получить его из магазина редуксов. Скажем также, что calculateFees гораздо сложнее, имеет более 10 видов сборов и используется десятками компонентов. Возможные варианты:

1) Передайте все сборы от класса, который его называет, который подключен к штату.

(например, calculateFees(itemPrice, feeOne, feeTwo, FeeThree, ...)

2) продублируйте код в каждом классе, который связан с состоянием редукса.

3) экспортировать весь магазин (или его часть), чтобы функция calculateFees могла получить доступ к данным через импорт.

4) Не уверен, что это вообще возможно, но создайте класс со статическими методами и подключите его к хранилищу редуксов. А затем используйте его, например, MyCompanyFees.calculateFees.

5) Создайте thunk, который извлекает данные только из состояния и возвращает рассчитанные сборы. Неправильно использовать это, поскольку он не асинхронный и не обновляет дерево состояний.

Я хотел бы получить некоторые рекомендации / предложения по подходу лучших практик, так как я не фанат 1, 2 или 3.

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

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

Прежде всего, вычисление должно быть отдельной функцией, которая получает все необходимые данные в качестве аргументов (таким образом, вы также можете легко их модульно протестировать) и не заботится, используется ли она в приложении React или вы используете Redux или что-то еще. Если вы думаете, что он будет вызываться несколько раз с одними и теми же аргументами, вы могли бы также прочитать концепцию, называемую «запоминание», но я думаю, что в большинстве случаев запоминание должно происходить вне этой функции.

Теперь, при условии, что у вас уже есть остальные данные (упомянутый вами consultingFee заполнитель) в вашем магазине, и вы хотите получить вычисленное значение после получения ответа от вашего бэкэнда. В этом случае вы можете извлечь значения из хранилища, как показано в ответе bsapaka, и поместить вычисленное значение в избыточное хранилище, к которому вы обращаетесь, где вам это нужно. Этого достаточно, если вы сделаете запрос один раз, отобразите вычисленное значение и все, вы знаете, что если вам нужно будет снова вычислить его, у вас будут разные входные значения и вам придется снова вызывать backend, и вам не нужно кэшировать результат, хотя я бы сказал, что в этом случае вам не следует хранить рассчитанное значение в вашем магазине.

Вы также можете использовать селектор дальше в функции mapStateToProps, для этого будет полезна повторная выборка библиотеки (обязательно прочитайте раздел «Совместное использование селекторов с реквизитами в нескольких компонентах» README). Таким образом, у вас есть компонент, который отправляет действие, которое получает необходимые данные из серверной части и помещает их в хранилище избыточных данных. В mapStateToProps вы используете запомненный селектор, который собирает все необходимые данные и вычисляет результат, который не будет пересчитан, пока не изменится ввод (в данном случае релевантные значения из избыточного хранилища). Я бы предпочел этот подход, так как он уменьшает побочные эффекты в Redux и кажется мне более декларативным, но я также предпочитаю использовать RedEx в качестве своего рода кеша с необработанными значениями, и если мне нужно извлечь из него значения, я использую запомненные селекторы.

0 голосов
/ 01 ноября 2018

Простая функция вычислений / утилит не должна знать, откуда берутся данные, и должна просто принимать ее в качестве аргумента:

const calculateFees = (itemPrice, consultingFee) => itemPrice * consultingFee

Если данные поступают из хранилища, тогда в селекторе следует вызывать calculateFees.

Селектор:

const getCalculatedFees = (state, { itemId }) => {
    const itemPrice = state.items[itemId].price;
    const consultingFee = state.consultingFee;

    return calculateFees(itemPrice, consultingFee);
}

Тогда селектор может использоваться компонентами или функциями, связанными с действием, такими как thunks и sagas.

Компонент:

connect(
    state => ({
        calculatedFees: getCalculatedFees(state)
    })
)(MyComponent)

Thunk:

const myAction = itemId => (dispatch, getState) => {
    const calculatedFee = getCalculatedFees(getState(), { itemId });

    // do stuff...
    dispatch(doSomethingElse(calculatedFee));
}

Saga:

function* mySaga({ itemId }) {
    const calculatedFee = yield select(getCalculatedFees, { itemId });

    // ...
}
...