Flux
React
Rx
const matrix_A = [
[0, 1, 2, 0, 1],
[0, 1, 1, 0, 0],
[0, 1, 1, 0, 0],
[0, 1, 3, 1, 1]];
import {expect} from 'chai';
import {initMatrix, setCellValue, setCols, setRows} from '../src/source/core.js';
describe('Matrix actions', () => {
it('should set value in matrix cell', () => {
const cols = 2;
const rows = 2;
const matrix = initMatrix(cols, rows);
expect(matrix).to.equal([
[0,0],
[0,0],
]);
})
it('should set value in matrix cell', () => {
const matrix = [
[0,0],
[0,0],
];
const changedMatrix = setCellValue(matrix, 0, 1, 12);
expect(changedMatrix).to.equal([
[0,12],
[0,0],
])
})
})
// '/src/source/core.js';
export const initMatrix = (rows, cols) => Array(rows).fill(Array(cols).fill(0));
export const setCellValue = (matrix, row, col, value) =>
matrix.map((rowValue, rowIndex) => {
if (rowIndex !== row) return rowValue;
return rowValue.map((colValue, colIndex) => {
return colIndex === col ? value : colValue;
})
});
describe('Matrix actions', () => {
/* ... */
it('should increase matrix column numbers', () => {
const matrix = [
[1, 0],
[0, 1],
];
const changedMatrix = setCols(matrix, 4);
expect(changedMatrix).to.equal([
[1, 0, 0, 0],
[0, 1, 0, 0],
]);
})
it('should increase matrix rows numbers', () => {
const matrix = [
[1, 0],
[0, 1],
];
const changedMatrix = setRows(matrix, 4);
expect(changedMatrix).to.equal([
[1, 0],
[0, 1],
[0, 0],
[0, 0],
]);
})
})
describe('Matrix actions', () => {
/* ... */
it('should decrease matrix column numbers', () => {
const matrix = [
[1, 0, 0, 0],
[0, 1, 0, 0],
];
const changedMatrix = setCols(matrix, 2);
expect(changedMatrix).to.equal([
[1, 0],
[0, 1],
]);
})
it('should decrease matrix rows numbers', () => {
const matrix = [
[1, 0],
[0, 1],
[0, 0],
[0, 0],
];
const changedMatrix = setRows(matrix, 2);
expect(changedMatrix).to.equal([
[1, 0],
[0, 1],
]);
})
})
// src/source/core.js
// тут все просто
export const setRows = (matrix, rows) => {
const res = [];
for (let rowIndex = 0; rowIndex < rows; rowIndex ++) {
const row = [];
for (let colIndex = 0; colIndex < matrix[0].length; colIndex++) {
row.push(matrix[rowIndex] ? matrix[rowIndex][colIndex] : 0);
}
res.push(rows);
}
return res;
}
export const setCols = (matrix, cols) => {
const res = [];
for (let rowIndex = 0; rowIndex < matrix.length; rowIndex ++) {
const row = [];
for (let colIndex = 0; colIndex < cols; colIndex++) {
row.push(matrix[rowIndex][colIndex] || 0);
}
res.push(rows);
}
return res;
}
describe('Matrix actions', () => {
/* ... */
it('should summarize 4 matrices', () => {
const matrix_A = [
[1, 0],
[0, 1],
];
const matrix_B = [
[1, 2],
[3, 1],
];
const matrix_C = [
[1, 0],
[0, 1],
];
const matrix_E = [
[1, 2],
[3, 1],
];
const result = matrixSum(matrix_A, matrix_B, matrix_C, matrix_E);
expect(result).to.deep.equal([
[4, 4],
[6, 4],
]);
});
})
const summarize = (matrix_A, matrix_B) =>
matrix_A.map((row, rowIndex) =>
row.map(
(value_A, colIndex) => value_A + matrix_B[rowIndex][colIndex]
)
);
export const matrixSum = (matrices) => {
return matrices.length ? matrices.reduce(summarize) : [];
}
const state = {
rows: 3,
cols: 3,
matrices: [],
result: [],
}
INIT_MATRIX -> app -> next state with computed result
SET_ROWS -> app -> next state with computed result
SET_CELL_VALLUE -> app -> next state with computed result
const actions = [
{type: INIT_MATRIX},
{type: INIT_MATRIX},
{type: SET_ROWS, rows: 3},
{type: SET_COLS, cols: 4},
{type: SET_CELL_VALUE, id: 0, row: 0, col: 0, value: 5},
{type: SET_CELL_VALUE, id: 0, row: 1, col: 2, value: 10},
{type: SET_CELL_VALUE, id: 0, row: 2, col: 2, value: 6},
{type: SET_CELL_VALUE, id: 1, row: 0, col: 0, value: 1},
{type: SET_CELL_VALUE, id: 1, row: 1, col: 1, value: 3},
{type: SET_CELL_VALUE, id: 1, row: 2, col: 1, value: 4},
{type: INIT_MATRIX},
{type: SET_CELL_VALUE, id: 2, row: 0, col: 0, value: 6},
{type: SET_CELL_VALUE, id: 2, row: 0, col: 1, value: 8},
{type: SET_CELL_VALUE, id: 2, row: 2, col: 0, value: 12},
];
const resultState = actions.reduce(reducer, INITIAL_STATE);
expect(resultState.result).to.deep.equal([
[12, 8, 0, 0],
[0, 3, 10, 0],
[12, 4, 6, 0],
]);
const reducer = (state, action) => next state
import {initMatrix} from './core';
const INITIAL_STATE = {
rows: 3,
cols: 3,
matrices: [],
result: [],
}
export default (state = INITIAL_STATE, action) => {
let nextState = state;
if (action.type === 'INIT_MATRIX')
nextState = {
...state,
matrices: state.matrices.concat([initMatrix(state.rows, state.cols)])
}
return nextState;
}
// Spread
var obj = {a: 1, b: 2, c: 3, d: 4};
var {a} = obj; // тоже самое что и var a = obj.a
var {a, ...other} = obj;
other // {b: 2, c: 3, d: 4};
var b = {a, ...other} // {a: 1, b: 2, c: 3, d: 4}
var arr = [1, 2, 3, 4];
var [a] = arr; // тоже что и var a = arr[0];
var [a, ...other] = arr;
other // [2, 3, 4];
var b = [a, ...other] // [1, 2, 3, 4];
import {initMatrix} from './core';
export const INITIAL_STATE = {
rows: 3,
cols: 3,
matrices: [],
result: [],
}
export default (state = INITIAL_STATE, action) => {
let nextState = state;
if (action.type === 'INIT_MATRIX')
nextState = {
...state,
matrices: [...state.matrices, initMatrix(state.rows, state.cols)]
}
return nextState;
}
import {expect} from 'chai';
import reducer from 'reducer';
const INITIAL_STATE = {
rows: 2,
cols: 2,
matrices: [],
result: [],
}
describe('Reducer test', () => {
it('should add matrix to matrices list', () => {
const action = {type: 'INIT_MATRIX'};
const nextState = reducer(INITIAL_STATE, action);
expect(nextState).to.deep.equal({
rows: 2,
cols: 2,
matrices: [
[[0, 0],
[0, 0]],
],
result: []
})
})
})
export default (state = INITIAL_STATE, action) => {
let nextState;
switch (action.type) {
case INIT_MATRIX:
nextState = {
...state,
matrices: [...state.matrices, initMatrix(state.rows, state.cols)]
}; break;
case SET_CELL_VALUE:
const matrix = state.matrices[action.id];
nextState = {
...state,
matrices: [
...state.matrices.slice(0, action.id),
setCellValue(matrix, action.row, action.col, action.value),
...state.matrices.slice(action.id + 1)
]
}; break;
default:
nextState = state;
}
return {
...nextState,
result: calcMatrices(nextState.matrices, summarize)
};
}
export default (state = INITIAL_STATE, action) => {
let nextState;
switch (action.type) {
case INIT_MATRIX:
nextState = {
...state,
matrices: [...state.matrices, initMatrix(state.rows, state.cols)]
}; break;
case SET_CELL_VALUE:
const matrix = state.matrices[action.id];
nextState = {
...state,
matrices: [
...state.matrices.slice(0, action.id),
setCellValue(matrix, action.row, action.col, action.value),
...state.matrices.slice(action.id + 1)
]
}; break;
case SET_ROWS:
nextState = {
...state,
rows: action.rows,
matrices: state.matrices.map(matrix => setRows(matrix, action.rows))
}; break;
case SET_COLS:
nextState = {
...state,
cols: action.cols,
matrices: state.matrices.map(matrix => setCols(matrix, action.cols))
}; break;
default:
nextState = state;
}
return {
...nextState,
result: calcMatrices(nextState.matrices, summarize)
};
}
import reducer from 'reducer.js';
const actions = [
{type: INIT_MATRIX},
{type: INIT_MATRIX},
{type: SET_ROWS, rows: 3},
{type: SET_COLS, cols: 4},
{type: SET_CELL_VALUE, id: 0, row: 0, col: 0, value: 5},
{type: SET_CELL_VALUE, id: 0, row: 1, col: 2, value: 10},
{type: SET_CELL_VALUE, id: 0, row: 2, col: 2, value: 6},
{type: SET_CELL_VALUE, id: 1, row: 0, col: 0, value: 1},
{type: SET_CELL_VALUE, id: 1, row: 1, col: 1, value: 3},
{type: SET_CELL_VALUE, id: 1, row: 2, col: 1, value: 4},
{type: INIT_MATRIX},
{type: SET_CELL_VALUE, id: 2, row: 0, col: 0, value: 6},
{type: SET_CELL_VALUE, id: 2, row: 0, col: 1, value: 8},
{type: SET_CELL_VALUE, id: 2, row: 2, col: 0, value: 12},
];
describe('It should work!', () => {
it('SHOULD WORK!', () => {
const result = actions.reduce(reducer, INITIAL_STATE);
expect(result.result).to.deep.equal([
[12, 8, 0, 0],
[0, 3, 10, 0],
[12, 4, 6, 0],
]);
});
});
// SET_CELL_VALUE
{type: 'SET_CELL_VALUE', id: 0, row: 1, col: 2, value: 12}
// Action creator
const cellCellValue = (id, row, col, value) =>
({type: 'SET_CELL_VALUE', id, row, col, value} )
// actions.js
export const initMatrix = () => ({type: 'INIT_MATRIX'});
export const setCellValue = (id, row, col, value) =>
({type: 'SET_CELL_VALUE', id, row, col, value});
export const setCols = (cols) => {
if (cols === 0) return;
return {type: 'SET_COLS', cols};
};
export const setRows = (rows) => {
if (rows === 0) return;
return {type: 'SET_ROWS', rows};
};
export default function (reducer, initialState) {
let state = initialState;
let listeners = [];
const getState = () => state;
const dispatch = action => {
state = reducer(state, action);
listeners.forEach(listener => listener())
};
const subscribe = listener => {
listeners.push(listener);
return () => {
listener = listeners.filter(l => l !== listener);
}
};
dispatch({});
return {getState, dispatch, subscribe}
}
import createStore from './source/store';
import reducer from './source/reducer';
import INITIAL_STATE from './source/default_state';
import createApp from './ui/app';
const store = createStore(reducer, INITIAL_STATE);
const app = createApp(store.getState(), store.dispatch);
const render = () => app.render(document.getElementById('app'));
store.subscribe(render);
render();
Action
Reducer
View
State
export default (state = INITIAL_STATE, action) => {
let nextState;
switch (action.type) {
case INIT_MATRIX:
nextState = {
...state,
matrices: [...state.matrices, initMatrix(state.rows, state.cols)]
}; break;
case SET_CELL_VALUE:
const matrix = state.matrices[action.id];
nextState = {
...state,
matrices: [
...state.matrices.slice(0, action.id),
setCellValue(matrix, action.row, action.col, action.value),
...state.matrices.slice(action.id + 1)
]
}; break;
default:
nextState = state;
}
return {
...nextState,
result: calcMatrices(nextState.matrices, summarize)
};
}
export default (state = INITIAL_STATE, action) => {
let nextState;
switch (action.type) {
case INIT_MATRIX:
nextState = state.update(
'matrices',
matrices => matrices.concat(initMatrix, state.get('rows'), state.get('cols'))
);
case SET_CELL_VALUE:
nextState = state.update(
'matrices',
matrices => matrices.setIn([action.id, action.row, action.col], action.val)
);break;
default:
nextState = state;
}
return nextState.set('result', calcMatrices(nextState.get('matrices'), summarize));
}
export default createReducer({
INIT_MATRIX: (state, action) => state.update(
'matrices',
matrices => matrices.concat(initMatrix, state.get('rows'), state.get('cols'))
),
SET_CELL_VALUE: (state, action) => state.update(
'matrices',
matrices => matrices.setIn([action.id, action.row, action.col], action.val)
);break;
}, INITIAL_STATE)
Action creators
const putUser = (id) => ({type: 'PUT_USER', id});
const deleteUser = (id) => ({type: 'DELETE_USER', id});
const getUser = (id) => ({type: 'GET_USER', id});
const PUT_USER = 'PUT_USER';
const DELETE_USER = 'DELETE_USER';
const GET_USER = 'GET_USER'
const putUser = (id) => ({type: PUT_USER, id});
const deleteUser = (id) => ({type: DELETE_USER, id});
const getUser = (id) => ({type: GET_USER, id});
State
Action
Reducer
Middleware
New action
View
export default function promiseMiddleware() {
return next => action => {
const { promise, type, ...rest } = action;
if (!promise) return next(action);
const SUCCESS = type;
const REQUEST = type + '_REQUEST';
const FAILURE = type + '_FAILURE';
next({...rest, type: REQUEST});
return promise
.then(res => {
next({...rest, res, type: SUCCESS});
return true;
})
.catch(error => {
next({...rest, error, type: FAILURE});
console.error(error.stack)
return false;
});
};
}
export const putUser = (id) => ({
type: PUT_USER,
promise: api.putUser(id),
id
})
{
type: PUT_USER,
res,
id
}
{
type: PUT_USER_FAILURE,
error
}
{
type: PUT_USER_REQUEST
}
export const getUserById = (id) => {
return {
[CALL_API]: {
types: [ REQUISITES_REQUEST, RECEIVES_REQUISITES, REQUISITES_REQUEST_FAILED ],
payload: [id],
entity: ENTITIES.USER,
method: 'GET',
},
};
};
{
type: REQUISITES_REQUEST
}
{
type: RECEIVES_REQUISITES,
response
}
{
type: REQUISITES_REQUEST_FAILED,
error
}