Created
January 24, 2018 16:18
-
-
Save AlexSchwabauer/5ddf6a4bf2149f67adcbda87d34a4a07 to your computer and use it in GitHub Desktop.
Functor Reason React Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module type OrderFilterArrayType = { | |
type t; | |
type filterName; | |
let reduceFilter: (filterName, array(t)) => array(t); | |
type itemID; | |
let getItemID: t => itemID; | |
let findOneIndex: (itemID, array(t)) => option(int); | |
}; | |
module Make = (Item: OrderFilterArrayType) => { | |
type item = Item.t; | |
module Component = { | |
type sortFn = (item, item) => int; | |
type orderAction = | |
| Randomize | |
| Reverse | |
| Reorder(array(item)) | |
| Sort(sortFn); | |
type action = | |
| Filter(Item.filterName) | |
| ResetFilter | |
| DeleteItem(Item.itemID) | |
| DeleteAll | |
| AddItems(array(item)) | |
| MutateOrder(orderAction); | |
type state = { | |
items: array(item), | |
filterHistory: array(Item.filterName) | |
}; | |
type renderProps = { | |
ordered: array(item), | |
filtered: array(item), | |
reverse: unit => unit, | |
randomize: unit => unit, | |
reorder: array(item) => unit, | |
filter: Item.filterName => unit, | |
resetFilter: unit => unit, | |
deleteItem: Item.itemID => unit, | |
deleteAll: unit => unit, | |
addItems: array(item) => unit, | |
filterHistory: array(Item.filterName), | |
sortCustomFn: sortFn => unit | |
}; | |
type renderFn = renderProps => ReasonReact.reactElement; | |
/* quick and dirty */ | |
let shuffleArray: array('a) => array('a) = [%bs.raw | |
"function shuffle (array) {\n var rng = Math.random\n \n var result = []\n \n for (var i = 0; i < array.length; ++i) {\n var j = Math.floor(rng() * (i + 1))\n \n if (j !== i) {\n result[i] = result[j]\n }\n \n result[j] = array[i]\n }\n \n return result\n }" | |
]; | |
/* apply all filters in the history one after the other */ | |
let applyFilters = (items, filterHistory) => | |
filterHistory |> Array.fold_left((items, filter) => Item.reduceFilter(filter, items), items); | |
let component = ReasonReact.reducerComponent("OrderFilterArrayComponent"); | |
let make = (~render: renderFn, ~items as initialItems: array(item), _children) => { | |
...component, | |
initialState: () => {items: initialItems, filterHistory: [||]}, | |
reducer: (action, state) => | |
ReasonReact.( | |
switch action { | |
| MutateOrder(Reverse) => Update({...state, items: Js.Array.reverseInPlace(state.items)}) | |
| MutateOrder(Sort(sortFn)) => | |
Update({...state, items: state.items |> Js.Array.sortInPlaceWith(sortFn)}) | |
| MutateOrder(Randomize) => Update({...state, items: shuffleArray(state.items)}) | |
| MutateOrder(Reorder(items)) => Update({...state, items}) | |
| Filter(name) => | |
Update({...state, filterHistory: Array.append(state.filterHistory, [|name|])}) | |
| ResetFilter => Update({...state, filterHistory: [||]}) | |
| AddItems(items) => | |
/* only add unique items. Maybe better with a Set */ | |
let currentIDs = state.items |> Array.map(Item.getItemID); | |
Update({ | |
...state, | |
items: | |
Array.append( | |
state.items, | |
items | |
|> Js.Array.filter( | |
(item) => ! (currentIDs |> Js.Array.includes(Item.getItemID(item))) | |
) | |
) | |
}) | |
| DeleteAll => Update({...state, items: [||]}) | |
| DeleteItem(id) => | |
switch (Item.findOneIndex(id, state.items)) { | |
| None => NoUpdate | |
| Some(index) => | |
Update({...state, items: state.items |> Js.Array.filteri((_, i) => index !== i)}) | |
} | |
} | |
), | |
render: ({send, state}) => | |
render({ | |
sortCustomFn: (sortFn) => send(MutateOrder(Sort(sortFn))), | |
ordered: state.items, | |
filtered: applyFilters(state.items, state.filterHistory), | |
reorder: (a) => send(MutateOrder(Reorder(a))), | |
reverse: () => send(MutateOrder(Reverse)), | |
filter: (a) => send(Filter(a)), | |
deleteItem: (a) => send(DeleteItem(a)), | |
deleteAll: (_) => send(DeleteAll), | |
addItems: (a) => send(AddItems(a)), | |
resetFilter: (_) => send(ResetFilter), | |
filterHistory: state.filterHistory, | |
randomize: () => send(MutateOrder(Randomize)) | |
}) | |
}; | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module ImageType = { | |
type t = Types.Image.t; | |
type filterName = | |
| Commented; | |
let reduceFilter = (f, items: array(t)) => | |
switch f { | |
| Commented => items |> Js.Array.filter((img) => img##hasComments); | |
}; | |
type itemID = int; | |
let getItemID = (item: t) => item##id; | |
let findOneIndex = (id, items) => | |
switch (items |> Js.Array.findIndex((item) => item##id === id)) { | |
| (-1) => None | |
| a => Some(a) | |
}; | |
}; | |
module Gallery = Functor.Make(ImageType); | |
/* then the application somewhere in a react tree...*/ | |
Gallery.( | |
<Component | |
items=myImageGalleryArray | |
render=( | |
({ordered, addItems, deleteAll, deleteItem, reverse, randomize, reorder, sortCustomFn}) => ReasonReact.stringToElement("Render something with all the render props") | |
) | |
/> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment