{"id":19083795,"url":"https://github.com/justgage/reason-todo-dojo","last_synced_at":"2026-06-18T08:32:10.420Z","repository":{"id":66952909,"uuid":"183555581","full_name":"justgage/reason-todo-dojo","owner":"justgage","description":"This is an example project of how to make ReasonReact project that people can hack on together","archived":false,"fork":false,"pushed_at":"2019-05-13T19:04:10.000Z","size":520,"stargazers_count":2,"open_issues_count":3,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-11-12T08:35:43.795Z","etag":null,"topics":["dojo","dojo-kata","reason-react","reasonml"],"latest_commit_sha":null,"homepage":"http://utah-reason-todo.surge.sh/","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/justgage.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-04-26T04:15:37.000Z","updated_at":"2019-05-13T21:04:47.000Z","dependencies_parsed_at":null,"dependency_job_id":"f8a8134c-fc47-4dbc-a74e-4b997d9f9ca8","html_url":"https://github.com/justgage/reason-todo-dojo","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/justgage/reason-todo-dojo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justgage%2Freason-todo-dojo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justgage%2Freason-todo-dojo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justgage%2Freason-todo-dojo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justgage%2Freason-todo-dojo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/justgage","download_url":"https://codeload.github.com/justgage/reason-todo-dojo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/justgage%2Freason-todo-dojo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34483277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dojo","dojo-kata","reason-react","reasonml"],"created_at":"2024-11-09T02:49:03.293Z","updated_at":"2026-06-18T08:32:10.398Z","avatar_url":"https://github.com/justgage.png","language":"OCaml","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Todo list Kata (code challenge)\n\nThe challenge is to create a todo list that you can:\n\n- [ ] Add items to.\n- [ ] Check off items\n- [ ] Filter items by completion status\n- [ ] Whatever you want!\n\nThis is to teach basic Reason and the React bindings (called ReasonReact).\n\n## Getting Started\n\n#### Setting up VSCode:\n\nWe recommend you use VSCode, you can search \"reasonml\" for an extension that supports Reason. We recommend: [\"OCaml and Reason IDE\"](https://marketplace.visualstudio.com/items?itemName=freebroccolo.reasonml)\n\n![Click the Top result of searching \"reason\" or if on Windows, the second.](https://cl.ly/7568476b5d2e/Image%2525202019-05-13%252520at%25252010.29.49%252520AM.png)\n\n#### Getting the app running\n\nTo get the app running you can do:\n\n```\nnpm i\nnpm start\n```\n\nThen open up http://localhost:1414\n\n#### Mob timer\n\nIf you're going to switch off with other people we reccomend a mob timer to help you remember to switch. Pick whatever\n- In browser: https://agility.jahed.io/timer.html\n- Mac app: http://mobster.cc/\n\n# Goals\n\n## Goal 1: Adding Todo items\n\nBasically you want to be able to add todo items to the todo list by typing something into the box and clicking add or pushing enter. Example:\n\n![Adding things](https://cl.ly/071c5b571d20/download/Screen%252520Recording%2525202019-05-13%252520at%25252006.39%252520AM.gif)\n\n**Hints:**\n\nThere's a lot of usefull functions in `Belt` which is like a lodash for any ReasonML project.\n\nNamely here's a few useful ones:\n\n```reason\n/* This will add something to the front of a list */\nList.add([1,2,3], -1) /* will return [-1, 1, 2, 3] */\n\n/* this will add something to the back of the list */\nList.concat([1,2,3], [4, 5, 6]) /* will return [1, 2, 3, 4, 5, 6] */\n```\n\nSolution: https://github.com/justgage/reason-todo-dojo/pull/4/files\n\n## Goal 2: Checking off items on the list\n\nAt this step you'll want to check items off the list.\n\n![Checking off items](https://cl.ly/c9d5ce5bc519/download/Screen%252520Recording%2525202019-05-13%252520at%25252010.23%252520AM.gif)\n\n**Tip 1:**\n\nthe `[]` by default are immutable linked lists. Indexing into them to change them doesn't work.\n\nTry using `Belt.List.mapWithIndex` to change one item. The type signiture is:\n\n```reasonml\nlet mapWithIndex: (list(todo), (int, todo) =\u003e todo) =\u003e list;\n```\n\n**Tip 2:**\n\nTo update one item of a record you do it like this:\n\n```\n{...record, thing: \"new value\"}\n```\n\n**Gotcha 2:**\n\nthe onClick function on dom element **must** take an event so if you don't care about this event so if you do this:\n\n```reasonml\n// ERROR! typing () means you're passing \"unit\", which isn't compatible with the event type.\n\u003cdiv onClick={() =\u003e Js.log(\"I clicked!\")}\u003e\u003c/div\u003e\n```\n\nIt will throw an error! So you have to do this:\n\n```reasonml\n/* throwing a `_` in front of a variable name lets ReasonML know that you want to ignore it. */\n\u003cdiv onClick={_ignoredEvent =\u003e Js.log(\"I clicked!\")}\u003e\u003c/div\u003e\n```\n\nSolution: https://github.com/justgage/reason-todo-dojo/pull/5/files\n\n## Stretch Goal: Items in tabs\n\nIn this you should have tabs at the top of the todo list that you can sort them by either done, pending or all.\n\nExample:\n\n![gif of clicking tabs](https://cl.ly/c7204f56e62f/Screen%252520Recording%2525202019-05-13%252520at%25252007.28%252520AM.gif)\n\nThis one is more of a stretch goal so I won't provide any tips but try to use a variant type to model your tabs: https://reasonml.github.io/docs/en/variant\n\n## Show off your stuff\n\nPlease show off your stuff by making pushing up a PR or deploying it here:\n\n```\nnpm run deploy\n```\n\nThen post your solutions in the UtahJS #reasonml channel: https://slack.utahjs.com/\n\n---\n\n\u003cbr /\u003e\n\u003cbr /\u003e\n\u003cbr /\u003e\n\n## ReasonML for JS programmers\n\nThere's a really great \"Cheat Sheet\" for JS to Reason Syntax. It's no replacement for\nactually learning the language but it's useful for people just trying to read ReasonML:\nhttps://reasonml.github.io/docs/en/syntax-cheatsheet\n\n## Reason Gotchas and new syntax\n\nReason can look a lot like JavaScript, however it's quite a bit different.\n\n## No single quotes\n\nIn ReasonML everything is double quotes. No more fights, just get used to it.\n\nSingle quotes are reserved for a single character like in C, and C++. This is not very useful\nin JavaScript however if you compile ReasonML to native it can be nice.\n\n## `let` is `const`\n\nIn Reason `let` is used instead of `const`.\n\nFor the most part you shouldn't need any mutable variables but if you _really_ do\nthere's ways to do it in the [ReasonML docs](https://reasonml.github.io/docs/en/mutation).\n\n## Automatic returns\n\nThere's no `return` keyword in ReasonML. The last line of a function always returns:\n\n```reasonml\n\nlet add = (x, y) =\u003e {\n  let solution = x + y;\n  solution; /* \u003c- this get's automatically returned */\n}\n```\n\n## Don't forget your `;`'s\n\nAgain, ReasonML doesn't allow you to omit semicolons, you just have to get used to it if you're used to leaving\nthem off. Currently the parser can get pretty confused when you omit them so make sure to look for them as it's\none of the most common source of hard to read compiler errors.\n\n### The `-\u003e` operator.\n\nReason has a cool operator called \"Pipe first\" or sometimes \"Fast Pipe\". Basically\nit lets you call any group of functions in a chaining style:\n\n```reason\n/* this is BuckleScript standard library, List is in it and many other modules */\n/* that support \"Pipe First\" style. */\nopen Belt;\n\n /* you could do this, but what do you name the variables??? */\nlet i = [1, 2, 3];\nlet ii = List.map(i, x =\u003e x * 2);\nlet iii = List.map(ii, x =\u003e x - 2);\n\n/* terser, but not very readable */\nlet i = List.map(\n  List.map([1, 2, 3], x =\u003e x * 2),\n  x =\u003e x - 2\n)\n\n/* More readable and compiles to the thing above */\nlet i =\n  [1, 2, 3]\n  -\u003eList.map(x =\u003e x * 2)\n  -\u003eList.map(x =\u003e x - 2)\n```\n\n## JSX differences\n\nBecause ReasonML is statically typed (in a way that doesn't allow polymorphism) you have to specify what type the children of a component are:\n\n```reasonml\n\u003cdiv\u003e\n  {React.string(\"Way 1\")}\n  \"Way 2\"-\u003eReact.string\n\u003c/div\u003e\n```\n\n## Reasons Module System\n\nAgain, the [official docs](https://reasonml.github.io/docs/en/module) are better\nthan this short explanation but ReasonML's module system is very different from JS.\n\nIn JavaScript it's file-path based. Meaning you have to point Webpack to the\nactual file using folder paths like `./App/App.js`. For example:\n\n```JS\nimport App from \"./App/App.js\";\nimport Math from '../lib/Math.js\"\n\nconst three = Math.add(1, 2);\n\u003cApp\u003e...\u003c/App\u003e\n```\n\nIn contrast ReasonML is a _global non-path based system_. Basically it works like this:\n\n```reason\n/* no imports! Just access the modules directly */\nlet three = Math.add(1,2);\n\u003cApp\u003e...\u003c/App\u003e\n```\n\nYou just forget the imports, and it finds it because the filename is `App.re` and `Math.re`!\n\nIf you have more questions about this, just ask! It can be confusing at times.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustgage%2Freason-todo-dojo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjustgage%2Freason-todo-dojo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjustgage%2Freason-todo-dojo/lists"}