fixing up docs
This commit is contained in:
Родитель
1e609dd408
Коммит
5654f8897a
|
@ -1,4 +1,4 @@
|
|||
# Web Bootcamp/Day in the Web
|
||||
# Frontend Bootcamp / Days in the Web
|
||||
|
||||
## Purpose of this workshop
|
||||
|
||||
|
@ -33,3 +33,34 @@ After the project loads in your browser, click on `Step 0 - HTML/CSS/JS`. Then g
|
|||
- [MDN Web Docs](https://developer.mozilla.org/en-US/)
|
||||
- [React Docs](https://reactjs.org/docs/getting-started.html)
|
||||
- [Thinking in React](https://reactjs.org/docs/thinking-in-react.html)
|
||||
|
||||
# Contributing
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
|
||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
||||
|
||||
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
|
||||
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
|
||||
provided by the bot. You will only need to do this once across all repos using our CLA.
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
|
||||
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
# Legal Notices
|
||||
|
||||
Microsoft and any contributors grant you a license to the Microsoft documentation and other content
|
||||
in this repository under the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode),
|
||||
see the [LICENSE](LICENSE) file, and grant you a license to any code in the repository under the [MIT License](https://opensource.org/licenses/MIT), see the
|
||||
[LICENSE-CODE](LICENSE-CODE) file.
|
||||
|
||||
Microsoft, Windows, Microsoft Azure and/or other Microsoft products and services referenced in the documentation
|
||||
may be either trademarks or registered trademarks of Microsoft in the United States and/or other countries.
|
||||
The licenses for this project do not grant you rights to use any Microsoft names, logos, or trademarks.
|
||||
Microsoft's general trademark guidelines can be found at http://go.microsoft.com/fwlink/?LinkID=254653.
|
||||
|
||||
Privacy information can be found at https://privacy.microsoft.com/en-us/
|
||||
|
||||
Microsoft and any contributors reserve all other rights, whether under their respective copyrights, patents,
|
||||
or trademarks, whether by implication, estoppel or otherwise.
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -184,6 +184,8 @@ Now that we have a function to increment out count, all that we have left is to
|
|||
|
||||
> Note the syntax is a bit different than HTML. `onclick="funcName()"` vs `onClick={this.funcName}`
|
||||
|
||||
> Also note that each Counter maintains its own state! You can modify the state insde of one without affect the others.
|
||||
|
||||
## Bonus: Using a Button component
|
||||
|
||||
Buttons are one of the most common components to write. They help abstract common styling, add icons or other decorations, and increase functionality (menu buttons etc). Using an existing Button component is as easy as importing it `import {Button} from './Button';` and replacing `<button></button>` with `<Button></Button>`. Lets take a quick look at button to see how it came together.
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,4 +1,4 @@
|
|||
# Thinking In React: Hierarchy and Building a Static Version
|
||||
# Building a Static Page
|
||||
|
||||
## Demo
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=142)}({0:function(e,t,n){"use strict";e.exports=n(42)},142:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){return o.a.createElement("footer",null,o.a.createElement("p",null,"footer"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return c(t,e),t.prototype.render=function(){return o.a.createElement("div",null)},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("div",null)},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(d,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(m,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=143)}({0:function(e,t,n){"use strict";e.exports=n(42)},143:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){return o.a.createElement("footer",null,o.a.createElement("p",null,"footer"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return c(t,e),t.prototype.render=function(){return o.a.createElement("div",null)},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("div",null)},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(d,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(m,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,4 +1,4 @@
|
|||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=141)}({0:function(e,t,n){"use strict";e.exports=n(42)},141:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){return o.a.createElement("footer",null,o.a.createElement("p",null,"footer"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return c(t,e),t.prototype.render=function(){return o.a.createElement("header",null,o.a.createElement("h1",null,"todos"),o.a.createElement("div",{className:"addTodo"},o.a.createElement("input",{className:"textfield",placeholder:"add todo"}),o.a.createElement("button",{className:"submit"},"Add")),o.a.createElement("nav",{className:"filter"},o.a.createElement("button",{className:"completed"},"all"),o.a.createElement("button",null,"active"),o.a.createElement("button",null,"completed")))},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("div",null)},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(d,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(m,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=142)}({0:function(e,t,n){"use strict";e.exports=n(42)},142:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){return o.a.createElement("footer",null,o.a.createElement("p",null,"footer"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return c(t,e),t.prototype.render=function(){return o.a.createElement("header",null,o.a.createElement("h1",null,"todos"),o.a.createElement("div",{className:"addTodo"},o.a.createElement("input",{className:"textfield",placeholder:"add todo"}),o.a.createElement("button",{className:"submit"},"Add")),o.a.createElement("nav",{className:"filter"},o.a.createElement("button",{className:"completed"},"all"),o.a.createElement("button",null,"active"),o.a.createElement("button",null,"completed")))},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("div",null)},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(d,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(m,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,4 +1,4 @@
|
|||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=132)}({0:function(e,t,n){"use strict";e.exports=n(42)},132:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){return o.a.createElement("footer",null,o.a.createElement("span",null,o.a.createElement("span",{className:"remaining"},"4")," items left"),o.a.createElement("button",{className:"submit"},"Clear Completed"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return c(t,e),t.prototype.render=function(){return o.a.createElement("header",null,o.a.createElement("h1",null,"todos"),o.a.createElement("div",{className:"addTodo"},o.a.createElement("input",{className:"textfield",placeholder:"add todo"}),o.a.createElement("button",{className:"submit"},"Add")),o.a.createElement("nav",{className:"filter"},o.a.createElement("button",{className:"completed"},"all"),o.a.createElement("button",null,"active"),o.a.createElement("button",null,"completed")))},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("li",{className:"todo"},o.a.createElement("label",null,o.a.createElement("input",{type:"checkbox"})," Todo 1"))},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){return o.a.createElement("ul",{className:"todos"},o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null))},t}(o.a.Component),h=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),y=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return h(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(m,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(y,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=133)}({0:function(e,t,n){"use strict";e.exports=n(42)},133:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){return o.a.createElement("footer",null,o.a.createElement("span",null,o.a.createElement("span",{className:"remaining"},"4")," items left"),o.a.createElement("button",{className:"submit"},"Clear Completed"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return c(t,e),t.prototype.render=function(){return o.a.createElement("header",null,o.a.createElement("h1",null,"todos"),o.a.createElement("div",{className:"addTodo"},o.a.createElement("input",{className:"textfield",placeholder:"add todo"}),o.a.createElement("button",{className:"submit"},"Add")),o.a.createElement("nav",{className:"filter"},o.a.createElement("button",{className:"completed"},"all"),o.a.createElement("button",null,"active"),o.a.createElement("button",null,"completed")))},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("li",{className:"todo"},o.a.createElement("label",null,o.a.createElement("input",{type:"checkbox"})," Todo 1"))},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){return o.a.createElement("ul",{className:"todos"},o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null))},t}(o.a.Component),h=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),y=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return h(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(m,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(y,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,20 +1,135 @@
|
|||
# Creating a State Driven UI
|
||||
|
||||
In React data travels two directions, top down in the form of state propegating throughout controls, and bottom up, as interacting with the UI flows back up to modify the state. When writing an application it's often helpful to think of these two directions as separate parts of the development process.
|
||||
|
||||
## demo
|
||||
|
||||
add state to AppTodo
|
||||
pass to header and list
|
||||
[Step #3 of Thinking in React](https://reactjs.org/docs/thinking-in-react.html) suggests finding the "minimal set of mutable state" that your application requires. So in this demo we are going to add that "minimal state" to our application and drive our UI off of that data. With that done the next step will be to create ways to modify that state, which will in turn cascade down through our UI. This [reconcilation](https://reactjs.org/docs/reconciliation.html) process, figuring out what in your UI needs to change based on changing state, is what React excels in.
|
||||
|
||||
### header
|
||||
### Adding State to App
|
||||
|
||||
- pull filter from props
|
||||
- update buttons with classNames for active
|
||||
- Add value/onChange to input
|
||||
For our minimal state, we're going to include just two keys: `todos` and `filter`. We don't need to worry about a `remaining` value because we can calculate that by looking at the number of unchecked todos.
|
||||
|
||||
### TodoList
|
||||
So here is our full constructor
|
||||
|
||||
- write map to loop through items, pass key and todos
|
||||
```jsx
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
todos: {
|
||||
'04': {
|
||||
label: 'Todo 4',
|
||||
completed: true
|
||||
},
|
||||
'03': {
|
||||
label: 'Todo 3',
|
||||
completed: false
|
||||
},
|
||||
'02': {
|
||||
label: 'Todo 2',
|
||||
completed: false
|
||||
},
|
||||
'01': {
|
||||
label: 'Todo 1',
|
||||
completed: false
|
||||
}
|
||||
},
|
||||
filter: 'all'
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
## exercise
|
||||
> You could use an array to represent your todos. Array manipulation can be easier in some cases, but this object approach simplifies other functionality and will ultimately be more performant.
|
||||
|
||||
update footer to include todos
|
||||
add item count and item(s)
|
||||
update ListItem, pull in props, use label/completed already passed in
|
||||
### Passing State Through to UI
|
||||
|
||||
To avoid reaching into state over and over, we once again use deconstruction to pull out the pieces we need.
|
||||
|
||||
```jsx
|
||||
const { filter, todos } = this.state;
|
||||
```
|
||||
|
||||
Now we can pass `filter` and `todos` into our components.
|
||||
|
||||
```jsx
|
||||
return (
|
||||
<div>
|
||||
<TodoHeader filter={filter} />
|
||||
<TodoList todos={todos} filter={filter} />
|
||||
<TodoFooter todos={todos} />
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
### State Driven TodoList
|
||||
|
||||
I've already pulled out our props into `filter` and `todos` variables, and written a bit of JS that will return an array of filtered todo `id`s. We'll be using that filtered array to render out todo items.
|
||||
|
||||
```jsx
|
||||
{
|
||||
filteredTodos.map(id => <TodoListItem key={id} id={id} {...todos[id]} />);
|
||||
}
|
||||
```
|
||||
|
||||
- A JavaScript map takes in an array and transforms it into a new array
|
||||
- We use the `id` from the `filterTodos` array as the [list key](https://reactjs.org/docs/lists-and-keys.html) to help React track each item as state changes.
|
||||
- The key is not actually passed into the component, so we pass the key in as `id` as well. This will help us out later.
|
||||
- Lastly we use the `id` to grab the todo from our `todos` object, then use the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) to pass through the todo's `label` and `completed` values.
|
||||
> This spread opperator is the same as saying `label={todos[id].label} completed={todos[id].completed}`. Pretty obvious why spread is so handy!
|
||||
|
||||
### State Driven and Stateful Header
|
||||
|
||||
Within the header we've got a situation where we not only want to pass `filter` state down to it, but we also want to maintain state within the control. Fortunatly, this is no problem at all for React. First off let's deal with the incoming state.
|
||||
|
||||
#### Conditional ClassNames
|
||||
|
||||
In CSS based styling, visual states are applied by adding and removing classes. We can use the filter value to conditionally add a class thereby lighting up the correct filter button.
|
||||
|
||||
```jsx
|
||||
<nav className="filter">
|
||||
<button className={filter == 'all' ? 'completed' : ''}>all</button>
|
||||
<button className={filter == 'active' ? 'completed' : ''}>active</button>
|
||||
<button className={filter == 'completed' ? 'completed' : ''}>completed</button>
|
||||
</nav>
|
||||
```
|
||||
|
||||
> Terniary operators are very popular in React code as each expression could be a string for a className, or even a JSX element.
|
||||
|
||||
#### Creating a Controled Input
|
||||
|
||||
In tradition HTML forms users interact with the form, and on submit, those values are captured and transmitted. Those are called **uncontrolled inputs**. A **controlled input** is one whos value is defined by state, and interaction with that input updates state with each keystroke. This round trip process might sound inefficient, but in reality it has little to no impact, and it enables some advanced form functionality.
|
||||
|
||||
To create a controlled component, we need two things, which our demo already provides:
|
||||
|
||||
1. A state variable to hold the input's value
|
||||
|
||||
```jsx
|
||||
this.state = { labelInput: '' };
|
||||
```
|
||||
|
||||
2. A function to update that value
|
||||
|
||||
```jsx
|
||||
_onChange = evt => {
|
||||
this.setState({ labelInput: evt.target.value });
|
||||
};
|
||||
```
|
||||
|
||||
With those two pieces in place, we can update our uncontrolled input to being controlled.
|
||||
|
||||
```jsx
|
||||
<input value={this.state.labelInput} onChange={this._onChange} className="textfield" placeholder="add todo" />
|
||||
```
|
||||
|
||||
## Exercise
|
||||
|
||||
### TodoFooter
|
||||
|
||||
1. Use the provided `itemCount` value drive the number of items left.
|
||||
2. Use a ternary operator to print `item` vs `items` based on if `itemCount > 1`
|
||||
|
||||
### TodoListItem
|
||||
|
||||
1. Pull in `label` and `completed` from props using [destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring)
|
||||
2. Set the todo's text to `label` and the `checked` prop to `completed`
|
||||
> Note that this is only half the work we need to do to make these controlled inputs. What is the other half?
|
||||
|
|
|
@ -7,6 +7,7 @@ export class TodoHeader extends React.Component<any, any> {
|
|||
}
|
||||
|
||||
render() {
|
||||
const { filter } = this.props;
|
||||
return (
|
||||
<header>
|
||||
<h1>todos</h1>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=133)}({0:function(e,t,n){"use strict";e.exports=n(42)},133:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){Object.keys(e.todos).filter(function(t){return!e.todos[t].completed}).length;return o.a.createElement("footer",null,o.a.createElement("span",null,"4 items left"),o.a.createElement("button",{className:"submit"},"Clear Completed"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(t){var n=e.call(this,t)||this;return n._onChange=function(e){n.setState({labelInput:e.target.value})},n.state={labelInput:""},n}return c(t,e),t.prototype.render=function(){return o.a.createElement("header",null,o.a.createElement("h1",null,"todos"),o.a.createElement("div",{className:"addTodo"},o.a.createElement("input",{className:"textfield",placeholder:"add todo"}),o.a.createElement("button",{className:"submit"},"Add")),o.a.createElement("nav",{className:"filter"},o.a.createElement("button",{className:"completed"},"all"),o.a.createElement("button",null,"active"),o.a.createElement("button",null,"completed")))},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("li",{className:"todo"},o.a.createElement("label",null,o.a.createElement("input",{type:"checkbox"})," Todo 1"))},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){var e=this.props,t=e.filter,n=e.todos;Object.keys(n).filter(function(e){return"all"===t||"completed"===t&&n[e].completed||"active"===t&&!n[e].completed});return o.a.createElement("ul",{className:"todos"},o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null))},t}(o.a.Component),h=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),y=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return h(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(m,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(y,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var l=t[r]={i:r,l:!1,exports:{}};return e[r].call(l.exports,l,l.exports,n),l.l=!0,l.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var l in e)n.d(r,l,function(t){return e[t]}.bind(null,l));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=134)}({0:function(e,t,n){"use strict";e.exports=n(42)},134:function(e,t,n){"use strict";n.r(t);var r,l=n(0),o=n.n(l),i=n(15),a=n.n(i),u=function(e){Object.keys(e.todos).filter(function(t){return!e.todos[t].completed}).length;return o.a.createElement("footer",null,o.a.createElement("span",null,"4 items left"),o.a.createElement("button",{className:"submit"},"Clear Completed"))},c=(r=function(e,t){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)},function(e,t){function n(){this.constructor=e}r(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}),s=function(e){function t(t){var n=e.call(this,t)||this;return n._onChange=function(e){n.setState({labelInput:e.target.value})},n.state={labelInput:""},n}return c(t,e),t.prototype.render=function(){this.props.filter;return o.a.createElement("header",null,o.a.createElement("h1",null,"todos"),o.a.createElement("div",{className:"addTodo"},o.a.createElement("input",{className:"textfield",placeholder:"add todo"}),o.a.createElement("button",{className:"submit"},"Add")),o.a.createElement("nav",{className:"filter"},o.a.createElement("button",{className:"completed"},"all"),o.a.createElement("button",null,"active"),o.a.createElement("button",null,"completed")))},t}(o.a.Component),f=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),d=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return f(t,e),t.prototype.render=function(){return o.a.createElement("li",{className:"todo"},o.a.createElement("label",null,o.a.createElement("input",{type:"checkbox"})," Todo 1"))},t}(o.a.Component),p=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),m=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return p(t,e),t.prototype.render=function(){var e=this.props,t=e.filter,n=e.todos;Object.keys(n).filter(function(e){return"all"===t||"completed"===t&&n[e].completed||"active"===t&&!n[e].completed});return o.a.createElement("ul",{className:"todos"},o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null),o.a.createElement(d,null))},t}(o.a.Component),h=function(){var e=function(t,n){return(e=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(t,n)};return function(t,n){function r(){this.constructor=t}e(t,n),t.prototype=null===n?Object.create(n):(r.prototype=n.prototype,new r)}}(),y=function(e){function t(){return null!==e&&e.apply(this,arguments)||this}return h(t,e),t.prototype.render=function(){return o.a.createElement("div",null,o.a.createElement(s,null),o.a.createElement(m,null),o.a.createElement(u,null))},t}(o.a.Component);a.a.render(o.a.createElement(y,null),document.getElementById("app"))},15:function(e,t,n){"use strict";!function e(){if("undefined"!=typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(e){console.error(e)}}(),e.exports=n(43)},16:function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},27:function(e,t,n){"use strict";
|
||||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -11,7 +11,7 @@ export class TodoList extends React.Component<any, any> {
|
|||
return (
|
||||
<ul className="todos">
|
||||
{filteredTodos.map(id => (
|
||||
<TodoListItem key={id} {...todos[id]} />
|
||||
<TodoListItem key={id} id={id} {...todos[id]} />
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,6 +1,11 @@
|
|||
import React from 'react';
|
||||
|
||||
export class TodoHeader extends React.Component<any, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { labelInput: '' };
|
||||
}
|
||||
|
||||
render() {
|
||||
const { filter } = this.props;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export class TodoList extends React.Component<any, any> {
|
|||
return (
|
||||
<ul className="todos">
|
||||
{filteredTodos.map(id => (
|
||||
<TodoListItem key={id} {...todos[id]} />
|
||||
<TodoListItem key={id} id={id} {...todos[id]} />
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,43 +1,188 @@
|
|||
already done
|
||||
Types in header
|
||||
TodoApp methods
|
||||
# Creating a UI Driven State
|
||||
|
||||
filteredTodos in List
|
||||
Now that we have a UI that is purely driven by the state of our app, we need to add functionality to allow the UI to drive the state. This is often done by creating functions that call `setState` like we saw in the `todoHeader`, that are passed down to the UI as props.
|
||||
|
||||
demo
|
||||
> We'll be learning in part 2 of this workshop how we can expose these functions without explicitly passing them down via props
|
||||
|
||||
## app
|
||||
This is our core 'business logic' and handles everything our basic 'CRUD' operations of "Create, Read, Update, Delete". We don't have time to walk through writing all of those functions, but you can see that they are already provided in the demo's `TodoApp` and passed into our components.
|
||||
|
||||
Add Types to TodoApp
|
||||
change 'filter' state value to demonstrate
|
||||
## Intro to Typescript
|
||||
|
||||
## List (open list next to app)
|
||||
Taking a look at our components in `TodoApp` you can see that our list of props is not just getting longer, but is getting much more complex! We're passing through functions with various signatures, complex `todos` objects as well as filter strings which are always one of three values.
|
||||
|
||||
Demo TodoApp.types
|
||||
Add Types in List
|
||||
As applications grow, it becomes increasing difficult to remember what each function does, or what each todo contains. Also, as JavaScript is a loosly type language, if I wanted to change the value of `todos` to an array inside my `TodoList`, javascript wouldn't care. But if `TodoListItems` was expecting an object, our application would break.
|
||||
|
||||
## App
|
||||
It is because of these two reasons that the entire industry is shifting to writing applications that are strongly typed, and are using Typescript to accomplish that.
|
||||
|
||||
Back to App, add complete={this.\_complete} to Todolist - show types, change complete to 'false', filter
|
||||
As [their website](https://www.typescriptlang.org/) state:
|
||||
|
||||
## List
|
||||
> Typescript is a superset of JavaScript that compiles to plain JavaScript
|
||||
|
||||
add complete, pass to item (prop drilling)
|
||||
If you've ever used [Sass](https://sass-lang.com/) you are familiar with this concept. In the same say that all valid CSS is valid Sass, all valid JavaScript is valid Typescript. That's why most of this project has been writting in `ts` and `tsx` files instead of `js` and `jsx` files.
|
||||
|
||||
## List Item (move List Item into App window)
|
||||
Let's dive into the demo and see how Typescript can help us better understand our component props, and guard against future regressions.
|
||||
|
||||
TodoListItemProps, extend, id, complete (possible abstraction)
|
||||
add props, add complete to List item
|
||||
## Demo
|
||||
|
||||
## List
|
||||
Let's start off in the TodoList, as that has the most data flow, up and down. There isn't any actionable UI in this component as we're simply passing `completed` down to each `TodoListItem`, but we can write a component interface to make sure that everything gets passed down properly.
|
||||
|
||||
Demo how you can't add random things to TodoListItem or item's this.props now
|
||||
### Writing TodoListProps
|
||||
|
||||
exercise
|
||||
Looking at our `TodoApp` we know that `TodoList` has three props, `filter`, `todos`, and `filter`. We'll start by creating and interface that represents this component's props called `TodoListProps`.
|
||||
|
||||
Add types to footer
|
||||
Add onClick to button
|
||||
Add types to header
|
||||
Add setFilter to filter buttons
|
||||
write onAdd function
|
||||
place onAdd to submit button
|
||||
```tsx
|
||||
interface TodoListProps {
|
||||
filter: any;
|
||||
todos: any;
|
||||
complete: any;
|
||||
}
|
||||
```
|
||||
|
||||
> Note that we're using the `any` keyword for now. This won't give us any type safety, but it does innumerate the valid props we can pass to this component.
|
||||
|
||||
With that interface written, we'll add it to our component class.
|
||||
|
||||
```tsx
|
||||
export class TodoList extends React.Component<TodoListProps, any>
|
||||
```
|
||||
|
||||
> Note that the first value in `<>` is for a props interface, and the second for state
|
||||
|
||||
Now that we have a typed component, let's go back to our `TodoApp` and see what happens if we try to change the name of a prop.
|
||||
|
||||
### Adding type safety
|
||||
|
||||
So far we've only established what our prop names are, not the values inside of them. Let's first look at `filter`, and see how we can improve that prop's type safety.
|
||||
|
||||
#### Filter Type
|
||||
|
||||
We know that filter shouldn't be an object, array or function, so we can specify it should always be a string like this:
|
||||
|
||||
```tsx
|
||||
interface TodoListProps {
|
||||
filter: string;
|
||||
todos: any;
|
||||
complete: any;
|
||||
}
|
||||
```
|
||||
|
||||
But since we know that the filter can be only one of three values, we can explicitly write it that way with [union types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#union-types):
|
||||
|
||||
```tsx
|
||||
interface TodoListProps {
|
||||
filter: 'all' | 'active' | 'completed';
|
||||
todos: any;
|
||||
complete: any;
|
||||
}
|
||||
```
|
||||
|
||||
Now try going back to `TodoApp` and changing the `filter` attribute in `TodoList` to something else.
|
||||
|
||||
#### Complete Type
|
||||
|
||||
The `complete` props isn't data, but rather a function. Fortunatly, Typescript can handle function types just as well as data.
|
||||
|
||||
```tsx
|
||||
interface TodoListProps {
|
||||
filter: 'all' | 'active' | 'completed';
|
||||
todos: any;
|
||||
complete: (id: string) => void;
|
||||
}
|
||||
```
|
||||
|
||||
For functions we are only concerned with the parameters passed in and the return value. You can see in the example above that the function takes in an `id` of type string, and returns `void`, which means it has no return.
|
||||
|
||||
### Todos Type
|
||||
|
||||
The `todos` prop is interesting in that `todos` is an object with a bunch of unknown keys. So here's what that interface would look like.
|
||||
|
||||
```tsx
|
||||
interface TodoListProps {
|
||||
filter: 'all' | 'active' | 'completed';
|
||||
todos: {
|
||||
[id: string]: {
|
||||
label: string;
|
||||
completed: boolean;
|
||||
};
|
||||
};
|
||||
complete: (id: string) => void;
|
||||
}
|
||||
```
|
||||
|
||||
> Note that the `[]` notation does not mean an array, it is a [computed property](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Computed_property_names) notation.
|
||||
|
||||
Now that our interface is complete, try changing the word 'all' in `filter === all` and see that VS Code will tell you this condition will always be false. Imagine you had a typo in that line and you couldn't understand why your filter wasn't working.
|
||||
|
||||
### Abstracting types
|
||||
|
||||
Most of our components are going to need to add types for `todos` and `filter`, so it's a good thing that Typescript allows us to abstract those. I've already written up and exported those shared types in the file `TodoApp.types.ts`, so we just need to import them and pull them into our interface.
|
||||
|
||||
```tsx
|
||||
import { FilterTypes, Todos } from '../TodoApp.types';
|
||||
|
||||
interface TodoListProps {
|
||||
complete: (id: string) => void;
|
||||
todos: Todos;
|
||||
filter: FilterTypes;
|
||||
}
|
||||
```
|
||||
|
||||
### Updating TodoApp
|
||||
|
||||
Our `TodoApp` doesn't take any props, but it does have state. We can use Typescript to define that as well.
|
||||
|
||||
I've already imported `Todos`, and `FilterTypes` into the `TodoApp`, so we just need to add them to our class. We can even skip the 'interface', if we want to, and add them directly to the class.
|
||||
|
||||
```tsx
|
||||
export class TodoApp extends React.Component<{}, { todos: Todos; filter: FilterTypes }>
|
||||
```
|
||||
|
||||
> Note that the first value in `<>` always refers to props. Since `TodoApp` takes none, we'll set it to an empty object.
|
||||
|
||||
### Writing TodoListItemProps
|
||||
|
||||
Jumping down to the TodoListItem, as we start to write the TodoListItemProps we realize that two of the props, `label` and `completed` have already been defined in the `TodoItem` interface in `TodoApp.types`. So in the same way we can reuse individual types (`FilterTypes`), we can reuse, and extend upon entire interfaces.
|
||||
|
||||
```tsx
|
||||
interface TodoListItemProps extends TodoItem {
|
||||
id: string;
|
||||
complete: (id: string) => void;
|
||||
}
|
||||
```
|
||||
|
||||
The end result of this is an interface with all 4 properties, `id`, `complete`, `completed` and `label`.
|
||||
|
||||
Next we can pull in the remaining props:
|
||||
|
||||
```jsx
|
||||
const { label, completed, complete, id } = this.props;
|
||||
```
|
||||
|
||||
And then use the input's `onChange` event to fire our `complete` callback. We can see in the signature that we expect and `id` of type string, so we'll pass our `id` prop in.
|
||||
|
||||
```tsx
|
||||
<input type="checkbox" checked={completed} onChange={() => complete(id)} />
|
||||
```
|
||||
|
||||
> Note that the function param and prop name just happen to be the same. This isn't required.
|
||||
|
||||
## Exercise
|
||||
|
||||
### TodoFooter
|
||||
|
||||
1. Open TodoFooter and write a TodoFooterProps interface. It should include two values, a function and an object. Assign this interface to props like this: `(props: TodoFooterProps)`
|
||||
2. Write an `_onClick` function that calls `props.clear`.
|
||||
> Since TodoFooter is not a class the `_onClick` needs to be declared as a const, and placed before the `return`.
|
||||
3. Add `_onClick` to the button's `onClick`. You won't need to use `this` since this isn't a class.
|
||||
> We can't assign our `clear` function directly to `onClick`. We always need to create a function that calls our callbacks. `() => props.clear()`
|
||||
4. Test out this functionality. Check a few todos complete and click the `Clear Completed` button
|
||||
|
||||
### TodoHeader
|
||||
|
||||
1. Open TodoHeader and write TodoHeaderProps which will include 3 values. Replace the first `any` with this interface.
|
||||
2. This component also has state. Write TodoHeaderState (there's just one item), and add this where the second `any` was.
|
||||
3. Add `_onFilter` to each of the filter buttons
|
||||
> Note that we can't add new parameters to onClick, but we can pull information from the event target!
|
||||
4. Write an `_onAdd` method that calls `addTodo` on the current `labelInput`, then sets the `labelInput` in state to an empty string
|
||||
5. Call `_onAdd` from the submit button
|
||||
6. Check out this new functionality! We can now add and filter todos!
|
||||
|
|
|
@ -26,8 +26,6 @@ export class TodoApp extends React.Component<any, any> {
|
|||
);
|
||||
}
|
||||
|
||||
// business logic
|
||||
|
||||
private _addTodo = label => {
|
||||
const { todos } = this.state;
|
||||
const id = index++;
|
||||
|
|
|
@ -17,9 +17,9 @@ export class TodoHeader extends React.Component<any, any> {
|
|||
<button className="submit">Add</button>
|
||||
</div>
|
||||
<nav className="filter">
|
||||
<button className={filter == 'all' ? 'completed' : ''}>all</button>
|
||||
<button className={filter == 'active' ? 'completed' : ''}>active</button>
|
||||
<button className={filter == 'completed' ? 'completed' : ''}>completed</button>
|
||||
<button className={filter == 'all' ? 'selected' : ''}>all</button>
|
||||
<button className={filter == 'active' ? 'selected' : ''}>active</button>
|
||||
<button className={filter == 'completed' ? 'selected' : ''}>completed</button>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -17,14 +17,18 @@ export class TodoHeader extends React.Component<any, any> {
|
|||
<button className="submit">Add</button>
|
||||
</div>
|
||||
<nav className="filter">
|
||||
<button className={filter == 'all' ? 'completed' : ''}>all</button>
|
||||
<button className={filter == 'active' ? 'completed' : ''}>active</button>
|
||||
<button className={filter == 'completed' ? 'completed' : ''}>completed</button>
|
||||
<button className={filter == 'all' ? 'selected' : ''}>all</button>
|
||||
<button className={filter == 'active' ? 'selected' : ''}>active</button>
|
||||
<button className={filter == 'completed' ? 'selected' : ''}>completed</button>
|
||||
</nav>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
_onFilter = evt => {
|
||||
this.props.setFilter(evt.target.textContet);
|
||||
};
|
||||
|
||||
_onChange = evt => {
|
||||
this.setState({ labelInput: evt.target.value });
|
||||
};
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -6,7 +6,7 @@ import { Todos, FilterTypes } from './TodoApp.types';
|
|||
|
||||
let index = 0;
|
||||
|
||||
export class TodoApp extends React.Component<any, { todos: Todos; filter: FilterTypes }> {
|
||||
export class TodoApp extends React.Component<{}, { todos: Todos; filter: FilterTypes }> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
|
@ -26,8 +26,6 @@ export class TodoApp extends React.Component<any, { todos: Todos; filter: Filter
|
|||
);
|
||||
}
|
||||
|
||||
// business logic
|
||||
|
||||
private _addTodo = label => {
|
||||
const { todos } = this.state;
|
||||
const id = index++;
|
||||
|
|
|
@ -7,12 +7,16 @@ interface TodoFooterProps {
|
|||
|
||||
export const TodoFooter = (props: TodoFooterProps) => {
|
||||
const itemCount = Object.keys(props.todos).filter(id => !props.todos[id].completed).length;
|
||||
const _onClick = () => {
|
||||
props.clear();
|
||||
};
|
||||
|
||||
return (
|
||||
<footer>
|
||||
<span>
|
||||
{itemCount} item{itemCount > 1 ? 's' : ''} left
|
||||
</span>
|
||||
<button onClick={() => props.clear()} className="submit">
|
||||
<button onClick={_onClick} className="submit">
|
||||
Clear Completed
|
||||
</button>
|
||||
</footer>
|
||||
|
|
|
@ -7,7 +7,11 @@ interface TodoHeaderProps {
|
|||
filter: FilterTypes;
|
||||
}
|
||||
|
||||
export class TodoHeader extends React.Component<TodoHeaderProps, any> {
|
||||
interface TodoHeaderState {
|
||||
labelInput: string;
|
||||
}
|
||||
|
||||
export class TodoHeader extends React.Component<TodoHeaderProps, TodoHeaderState> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { labelInput: '' };
|
||||
|
@ -25,13 +29,13 @@ export class TodoHeader extends React.Component<TodoHeaderProps, any> {
|
|||
</button>
|
||||
</div>
|
||||
<nav className="filter">
|
||||
<button onClick={() => setFilter('all')} className={filter == 'all' ? 'completed' : ''}>
|
||||
<button onClick={this._onFilter} className={filter == 'all' ? 'selected' : ''}>
|
||||
all
|
||||
</button>
|
||||
<button onClick={() => setFilter('active')} className={filter == 'active' ? 'completed' : ''}>
|
||||
<button onClick={this._onFilter} className={filter == 'active' ? 'selected' : ''}>
|
||||
active
|
||||
</button>
|
||||
<button onClick={() => setFilter('completed')} className={filter == 'completed' ? 'completed' : ''}>
|
||||
<button onClick={this._onFilter} className={filter == 'completed' ? 'selected' : ''}>
|
||||
completed
|
||||
</button>
|
||||
</nav>
|
||||
|
@ -39,6 +43,10 @@ export class TodoHeader extends React.Component<TodoHeaderProps, any> {
|
|||
);
|
||||
}
|
||||
|
||||
_onFilter = evt => {
|
||||
this.props.setFilter(evt.target.textContet);
|
||||
};
|
||||
|
||||
_onChange = evt => {
|
||||
this.setState({ labelInput: evt.target.value });
|
||||
};
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,2 +1,2 @@
|
|||
!function(n){var t={};function e(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return n[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}e.m=n,e.c=t,e.d=function(n,t,o){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(e.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var r in n)e.d(o,r,function(t){return n[t]}.bind(null,r));return o},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=126)}({126:function(n,t,e){"use strict";e.r(t);var o,r=(o=function(n,t){return(o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,t){n.__proto__=t}||function(n,t){for(var e in t)t.hasOwnProperty(e)&&(n[e]=t[e])})(n,t)},function(n,t){function e(){this.constructor=n}o(n,t),n.prototype=null===t?Object.create(t):(e.prototype=t.prototype,new e)}),l=function(){return function(){}}();(function(n){function t(){return null!==n&&n.apply(this,arguments)||this}r(t,n)})(l),function(n){function t(){return null!==n&&n.apply(this,arguments)||this}r(t,n)}(l);var u={hello:"world"},c=function(){return function(){this.hello="world"}}();console.log(5),console.log(5),console.log(5),console.log(u),console.log(10),console.log(5),console.log(5),console.log(u),console.log(10),console.log((new c).hello),console.log((new c).hello);var i=function(){function n(){this.data=[]}return n.prototype.push=function(n){this.data.push(n)},n.prototype.pop=function(){return this.data.pop()},n}();new i,new i;var a=function(n,t,e,o){return new(e||(e=Promise))(function(r,l){function u(n){try{i(o.next(n))}catch(n){l(n)}}function c(n){try{i(o.throw(n))}catch(n){l(n)}}function i(n){n.done?r(n.value):new e(function(t){t(n.value)}).then(u,c)}i((o=o.apply(n,t||[])).next())})},f=function(n,t){var e,o,r,l,u={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]};return l={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(l[Symbol.iterator]=function(){return this}),l;function c(l){return function(c){return function(l){if(e)throw new TypeError("Generator is already executing.");for(;u;)try{if(e=1,o&&(r=2&l[0]?o.return:l[0]?o.throw||((r=o.return)&&r.call(o),0):o.next)&&!(r=r.call(o,l[1])).done)return r;switch(o=0,r&&(l=[2&l[0],r.value]),l[0]){case 0:case 1:r=l;break;case 4:return u.label++,{value:l[1],done:!1};case 5:u.label++,o=l[1],l=[0];continue;case 7:l=u.ops.pop(),u.trys.pop();continue;default:if(!(r=(r=u.trys).length>0&&r[r.length-1])&&(6===l[0]||2===l[0])){u=0;continue}if(3===l[0]&&(!r||l[1]>r[0]&&l[1]<r[3])){u.label=l[1];break}if(6===l[0]&&u.label<r[1]){u.label=r[1],r=l;break}if(r&&u.label<r[2]){u.label=r[2],u.ops.push(l);break}r[2]&&u.ops.pop(),u.trys.pop();continue}l=t.call(n,u)}catch(n){l=[6,n],o=0}finally{e=r=0}if(5&l[0])throw l[1];return{value:l[0]?l[1]:void 0,done:!0}}([l,c])}}};(function(){return a(this,void 0,void 0,function(){return f(this,function(n){switch(n.label){case 0:return[4,fetch("http://localhost:3000/hello")];case 1:return[4,n.sent().text()];case 2:return[2,n.sent()]}})})})().then(function(n){console.log("hello "+n)});var s=function(){return(s=Object.assign||function(n){for(var t,e=1,o=arguments.length;e<o;e++)for(var r in t=arguments[e])Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}).apply(this,arguments)},p=[1,2,3,4],h=p[0],y=p[1],b=p.slice(2);console.log(h,y,b);var d=[1,2];d=d.concat([3,4]),console.log(d);s({},{x:1,y:2},{z:3}),s({},{x:1},{y:2}).x}});
|
||||
!function(n){var t={};function e(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return n[o].call(r.exports,r,r.exports,e),r.l=!0,r.exports}e.m=n,e.c=t,e.d=function(n,t,o){e.o(n,t)||Object.defineProperty(n,t,{enumerable:!0,get:o})},e.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},e.t=function(n,t){if(1&t&&(n=e(n)),8&t)return n;if(4&t&&"object"==typeof n&&n&&n.__esModule)return n;var o=Object.create(null);if(e.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:n}),2&t&&"string"!=typeof n)for(var r in n)e.d(o,r,function(t){return n[t]}.bind(null,r));return o},e.n=function(n){var t=n&&n.__esModule?function(){return n.default}:function(){return n};return e.d(t,"a",t),t},e.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},e.p="",e(e.s=127)}({127:function(n,t,e){"use strict";e.r(t);var o,r=(o=function(n,t){return(o=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,t){n.__proto__=t}||function(n,t){for(var e in t)t.hasOwnProperty(e)&&(n[e]=t[e])})(n,t)},function(n,t){function e(){this.constructor=n}o(n,t),n.prototype=null===t?Object.create(t):(e.prototype=t.prototype,new e)}),l=function(){return function(){}}();(function(n){function t(){return null!==n&&n.apply(this,arguments)||this}r(t,n)})(l),function(n){function t(){return null!==n&&n.apply(this,arguments)||this}r(t,n)}(l);var u={hello:"world"},c=function(){return function(){this.hello="world"}}();console.log(5),console.log(5),console.log(5),console.log(u),console.log(10),console.log(5),console.log(5),console.log(u),console.log(10),console.log((new c).hello),console.log((new c).hello);var i=function(){function n(){this.data=[]}return n.prototype.push=function(n){this.data.push(n)},n.prototype.pop=function(){return this.data.pop()},n}();new i,new i;var a=function(n,t,e,o){return new(e||(e=Promise))(function(r,l){function u(n){try{i(o.next(n))}catch(n){l(n)}}function c(n){try{i(o.throw(n))}catch(n){l(n)}}function i(n){n.done?r(n.value):new e(function(t){t(n.value)}).then(u,c)}i((o=o.apply(n,t||[])).next())})},f=function(n,t){var e,o,r,l,u={label:0,sent:function(){if(1&r[0])throw r[1];return r[1]},trys:[],ops:[]};return l={next:c(0),throw:c(1),return:c(2)},"function"==typeof Symbol&&(l[Symbol.iterator]=function(){return this}),l;function c(l){return function(c){return function(l){if(e)throw new TypeError("Generator is already executing.");for(;u;)try{if(e=1,o&&(r=2&l[0]?o.return:l[0]?o.throw||((r=o.return)&&r.call(o),0):o.next)&&!(r=r.call(o,l[1])).done)return r;switch(o=0,r&&(l=[2&l[0],r.value]),l[0]){case 0:case 1:r=l;break;case 4:return u.label++,{value:l[1],done:!1};case 5:u.label++,o=l[1],l=[0];continue;case 7:l=u.ops.pop(),u.trys.pop();continue;default:if(!(r=(r=u.trys).length>0&&r[r.length-1])&&(6===l[0]||2===l[0])){u=0;continue}if(3===l[0]&&(!r||l[1]>r[0]&&l[1]<r[3])){u.label=l[1];break}if(6===l[0]&&u.label<r[1]){u.label=r[1],r=l;break}if(r&&u.label<r[2]){u.label=r[2],u.ops.push(l);break}r[2]&&u.ops.pop(),u.trys.pop();continue}l=t.call(n,u)}catch(n){l=[6,n],o=0}finally{e=r=0}if(5&l[0])throw l[1];return{value:l[0]?l[1]:void 0,done:!0}}([l,c])}}};(function(){return a(this,void 0,void 0,function(){return f(this,function(n){switch(n.label){case 0:return[4,fetch("http://localhost:3000/hello")];case 1:return[4,n.sent().text()];case 2:return[2,n.sent()]}})})})().then(function(n){console.log("hello "+n)});var s=function(){return(s=Object.assign||function(n){for(var t,e=1,o=arguments.length;e<o;e++)for(var r in t=arguments[e])Object.prototype.hasOwnProperty.call(t,r)&&(n[r]=t[r]);return n}).apply(this,arguments)},p=[1,2,3,4],h=p[0],y=p[1],b=p.slice(2);console.log(h,y,b);var d=[1,2];d=d.concat([3,4]),console.log(d);s({},{x:1,y:2},{z:3}),s({},{x:1},{y:2}).x}});
|
||||
//# sourceMappingURL=demo.js.map
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,2 +1,2 @@
|
|||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=120)}({120:function(e,t){var n=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,u){function i(e){try{a(r.next(e))}catch(e){u(e)}}function l(e){try{a(r.throw(e))}catch(e){u(e)}}function a(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(i,l)}a((r=r.apply(e,t||[])).next())})},r=this&&this.__generator||function(e,t){var n,r,o,u,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return u={next:l(0),throw:l(1),return:l(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function l(u){return function(l){return function(u){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&u[0]?r.return:u[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,u[1])).done)return o;switch(r=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return i.label++,{value:u[1],done:!1};case 5:i.label++,r=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(!(o=(o=i.trys).length>0&&o[o.length-1])&&(6===u[0]||2===u[0])){i=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){i.label=u[1];break}if(6===u[0]&&i.label<o[1]){i.label=o[1],o=u;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(u);break}o[2]&&i.ops.pop(),i.trys.pop();continue}u=t.call(e,i)}catch(e){u=[6,e],r=0}finally{n=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,l])}}};console.log("hello world"),function(){n(this,void 0,void 0,function(){return r(this,function(e){return[2]})})}()}});
|
||||
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=121)}({121:function(e,t){var n=this&&this.__awaiter||function(e,t,n,r){return new(n||(n=Promise))(function(o,u){function i(e){try{a(r.next(e))}catch(e){u(e)}}function l(e){try{a(r.throw(e))}catch(e){u(e)}}function a(e){e.done?o(e.value):new n(function(t){t(e.value)}).then(i,l)}a((r=r.apply(e,t||[])).next())})},r=this&&this.__generator||function(e,t){var n,r,o,u,i={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return u={next:l(0),throw:l(1),return:l(2)},"function"==typeof Symbol&&(u[Symbol.iterator]=function(){return this}),u;function l(u){return function(l){return function(u){if(n)throw new TypeError("Generator is already executing.");for(;i;)try{if(n=1,r&&(o=2&u[0]?r.return:u[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,u[1])).done)return o;switch(r=0,o&&(u=[2&u[0],o.value]),u[0]){case 0:case 1:o=u;break;case 4:return i.label++,{value:u[1],done:!1};case 5:i.label++,r=u[1],u=[0];continue;case 7:u=i.ops.pop(),i.trys.pop();continue;default:if(!(o=(o=i.trys).length>0&&o[o.length-1])&&(6===u[0]||2===u[0])){i=0;continue}if(3===u[0]&&(!o||u[1]>o[0]&&u[1]<o[3])){i.label=u[1];break}if(6===u[0]&&i.label<o[1]){i.label=o[1],o=u;break}if(o&&i.label<o[2]){i.label=o[2],i.ops.push(u);break}o[2]&&i.ops.pop(),i.trys.pop();continue}u=t.call(e,i)}catch(e){u=[6,e],r=0}finally{n=o=0}if(5&u[0])throw u[1];return{value:u[0]?u[1]:void 0,done:!0}}([u,l])}}};console.log("hello world"),function(){n(this,void 0,void 0,function(){return r(this,function(e){return[2]})})}()}});
|
||||
//# sourceMappingURL=exercise.js.map
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -8,9 +8,10 @@ A CodePen that illustrates what `mergeStyles` does: https://codepen.io/dzearing/
|
|||
|
||||
There are three areas that we should focus on in this step:
|
||||
|
||||
1. Theming with Fabric
|
||||
2. CSS-in-JS with mergeStyles
|
||||
3. Customizing Fabric Components `styles` prop
|
||||
1. Theming with Fabric using `<Customizer>` component
|
||||
2. Customizing themes and loading with `loadTheme()`
|
||||
3. CSS-in-JS with mergeStyles
|
||||
4. Customizing Fabric Components `styles` prop
|
||||
|
||||
## 1. Theming with Fabric
|
||||
|
||||
|
@ -19,40 +20,11 @@ There are three areas that we should focus on in this step:
|
|||
- There are some predefined themes within Fabric already, like Fluent (which will become the default in the next major), MDL2, Azure, and some other sample themes like Teams.
|
||||
- Take a look at `demo/src/components/TodoApp.tsx`
|
||||
|
||||
## 2. CSS-in-JS with mergeStyles
|
||||
## 2. Customizing Fabric Themes
|
||||
|
||||
- `mergeStyles` is a styling library that creates CSS class from styles that are expressed in JS
|
||||
- These classes can be passed into `className` prop of any component like `<div>`
|
||||
- This library replaces the need to import CSS stylesheets because they are bundled as normal JS code
|
||||
- Take a look at `demo/src/components/TodoApp.tsx`
|
||||
|
||||
## 3. Customizing Fabric Controls
|
||||
|
||||
- calling `mergeStyles` is time consuming and very static
|
||||
- Fabric components expose a `styles` prop (not to be confused with the React built-in one called `style`)
|
||||
- You can use intellisense to discover which parts of the component you can to customize
|
||||
- You can even use a style function to change the style based on some style prop
|
||||
- Take a look at these customizations in `demo/src/components/TodoHeader.tsx`
|
||||
|
||||
# Exercises
|
||||
|
||||
## Themes - Using Predefined Theme
|
||||
|
||||
Apply some included and predefined themes from the UI Fabric package inside the `/step2-03/exercise/src/components/TodoApp.tsx`. Do this by replacing:
|
||||
|
||||
```ts
|
||||
import { FluentCustomizations } from '@uifabric/fluent-theme';
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```ts
|
||||
import { TeamsCustomizations } from '@uifabric/theme-samples';
|
||||
```
|
||||
|
||||
## Themes - Customized Theme
|
||||
|
||||
Create your own theme and apply the color here: https://developer.microsoft.com/en-us/fabric#/styles/themegenerator
|
||||
- Use the `loadTheme()` function to load a theme (applies to entire application):
|
||||
- Erase the `<Customizer>` inside the `TodoApp.tsx` and place this code in the module scope. This will initialize a theme to be used throughout the application
|
||||
- Fabric website has a handy theme generator to get you started with a theme: https://developer.microsoft.com/en-us/fabric#/styles/themegenerator
|
||||
|
||||
```ts
|
||||
import { loadTheme } from 'office-ui-fabric-react';
|
||||
|
@ -85,6 +57,42 @@ loadTheme({
|
|||
});
|
||||
```
|
||||
|
||||
## 3. CSS-in-JS with mergeStyles
|
||||
|
||||
- `mergeStyles` is a styling library that creates CSS class from styles that are expressed in JS
|
||||
- These classes can be passed into `className` prop of any component like `<div>`
|
||||
- This library replaces the need to import CSS stylesheets because they are bundled as normal JS code
|
||||
- Take a look at `demo/src/components/TodoApp.tsx`
|
||||
|
||||
## 4. Customizing Fabric Controls
|
||||
|
||||
- calling `mergeStyles` is time consuming and very static
|
||||
- Fabric components expose a `styles` prop (not to be confused with the React built-in one called `style`)
|
||||
- You can use intellisense to discover which parts of the component you can to customize
|
||||
- You can even use a style function to change the style based on some style prop
|
||||
- Take a look at these customizations in `demo/src/components/TodoHeader.tsx`
|
||||
|
||||
# Exercises
|
||||
|
||||
## Themes - Using Predefined Theme
|
||||
|
||||
Apply some included and predefined themes from the UI Fabric package inside the `/step2-03/exercise/src/components/TodoApp.tsx`. Do this by replacing:
|
||||
|
||||
```ts
|
||||
import { FluentCustomizations } from '@uifabric/fluent-theme';
|
||||
```
|
||||
|
||||
with:
|
||||
|
||||
```ts
|
||||
import { TeamsCustomizations } from '@uifabric/theme-samples';
|
||||
```
|
||||
|
||||
## Themes - Customized Theme
|
||||
|
||||
Create your own theme and apply the color palette here:
|
||||
https://developer.microsoft.com/en-us/fabric#/styles/themegenerator
|
||||
|
||||
1. Delete the `Customizer` component
|
||||
|
||||
2. Paste in this code in the `TodoApp.tsx` before the `TodoApp` component definition
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -14,6 +14,8 @@ https://jestjs.io/
|
|||
|
||||
# Demo
|
||||
|
||||
## jest basics
|
||||
|
||||
In this repo, we can start an inner loop development of tests with the command: `npm test`
|
||||
|
||||
Take a look at code inside `demo/src`:
|
||||
|
@ -24,10 +26,43 @@ Take a look at code inside `demo/src`:
|
|||
|
||||
3. `index.spec.ts` is the test file: note how tests are re-run on save to test file changes as well as source code changes under `src`
|
||||
|
||||
## testing React applications
|
||||
|
||||
You can also test React Components with `jest` with the help of a partner library called `enzyme`. Take a look at the test below:
|
||||
|
||||
```ts
|
||||
import { mount } from 'enzyme';
|
||||
|
||||
describe('Foo Component Tests', () => {
|
||||
it('allows us to set props', () => {
|
||||
const wrapper = mount(<Foo bar="baz" />);
|
||||
expect(wrapper.props().bar).toBe('baz');
|
||||
wrapper.setProps({ bar: 'foo' });
|
||||
expect(wrapper.props().bar).toBe('foo');
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
`mount` does a full mount of the component. You can use the `enzyme` wrapper to simulate clicks, etc:
|
||||
|
||||
```ts
|
||||
wrapper.find('button').simulate('click');
|
||||
```
|
||||
|
||||
# Exercise
|
||||
|
||||
## Basic Testing
|
||||
|
||||
1. Run the tests by running `npm test` at the root of the bootcamp project
|
||||
|
||||
2. Look at the `stack.ts` for a sample implementation of a stack
|
||||
|
||||
3. Follow the instructions inside the `stack.spec.ts` file to complete the two tests
|
||||
|
||||
## Enzyme Testing
|
||||
|
||||
1. Open up `exercise/src/TestMe.spec.tsx`
|
||||
|
||||
2. Fill in the blank for the missing test using `enzyme` concepts introduced from the demo
|
||||
|
||||
3. Run tests with `npm test`
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { TestMe } from './TestMe';
|
||||
|
||||
describe('TestMe Component', () => {
|
||||
it('should have a non-clickable component when the origina InnerMe is clicked', () => {
|
||||
const wrapper = mount(<TestMe name="world" />);
|
||||
wrapper.find('#innerMe').simulate('click');
|
||||
expect(wrapper.find('#innerMe').text()).toBe('Clicked');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,37 @@
|
|||
import React from 'react';
|
||||
|
||||
export interface TestMeProps {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface TestMeState {
|
||||
clicked: boolean;
|
||||
}
|
||||
|
||||
export const TestMe = (props: TestMeProps) => {
|
||||
return (
|
||||
<div id="testMe">
|
||||
<InnerMe name={props.name} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export class InnerMe extends React.Component<TestMeProps, TestMeState> {
|
||||
state = {
|
||||
clicked: false
|
||||
};
|
||||
|
||||
onClick = () => {
|
||||
this.setState({ clicked: true });
|
||||
};
|
||||
|
||||
render() {
|
||||
return !this.state.clicked ? (
|
||||
<div onClick={this.onClick} id="innerMe">
|
||||
Hello {this.props.name}, Click Me
|
||||
</div>
|
||||
) : (
|
||||
<div id="innerMe">Clicked</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
!function(n){var e={};function t(r){if(e[r])return e[r].exports;var u=e[r]={i:r,l:!1,exports:{}};return n[r].call(u.exports,u,u.exports,t),u.l=!0,u.exports}t.m=n,t.c=e,t.d=function(n,e,r){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:r})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var u in n)t.d(r,u,function(e){return n[e]}.bind(null,u));return r},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=148)}({148:function(n,e,t){"use strict";t.r(e),t.d(e,"getCount",function(){return u}),t.d(e,"increment",function(){return o}),t.d(e,"decrement",function(){return i}),t.d(e,"square",function(){return f});var r=0;function u(){return r}function o(){return++r}function i(){return--r}function f(n){return function(n,e){return n*e}(n,n)}}});
|
||||
!function(n){var e={};function t(r){if(e[r])return e[r].exports;var u=e[r]={i:r,l:!1,exports:{}};return n[r].call(u.exports,u,u.exports,t),u.l=!0,u.exports}t.m=n,t.c=e,t.d=function(n,e,r){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:r})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var u in n)t.d(r,u,function(e){return n[e]}.bind(null,u));return r},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=149)}({149:function(n,e,t){"use strict";t.r(e),t.d(e,"getCount",function(){return u}),t.d(e,"increment",function(){return o}),t.d(e,"decrement",function(){return i}),t.d(e,"square",function(){return f});var r=0;function u(){return r}function o(){return++r}function i(){return--r}function f(n){return function(n,e){return n*e}(n,n)}}});
|
||||
//# sourceMappingURL=demo.js.map
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -2,17 +2,17 @@
|
|||
|
||||
[Lessons](../) | [Exercise](./exercise/) | [Demo](./demo/)
|
||||
|
||||
Redux is an implementation of the Flux architectural pattern:
|
||||
|
||||
![Flux Diagram](../assets/flux.png)
|
||||
|
||||
Ideally React gives us a mental model of:
|
||||
|
||||
```
|
||||
f(data) => view
|
||||
```
|
||||
|
||||
And it renders when data changes. However, in the real world, data is shaped like a tree and view is shaped like a tree. They don't always match. There are many approaches to Flux, but Redux promotes the data into a singleton state tree that listens for messages to manipulate the state as appropriate.
|
||||
This is fine if the data never changes. However, React exists to deal with data updates via props (immutable) and state (changes based on `setState()` API). In the real world, data is shaped like a tree and view is shaped like a tree. They don't always match.
|
||||
|
||||
Facebook invented a the Flux pattern to solve this shared state issue. Redux is an implementation of the Flux architectural pattern. Redux expects the data to be a singleton state tree that listens for messages to manipulate the state as appropriate:
|
||||
|
||||
![Flux Diagram](../assets/flux.png)
|
||||
|
||||
## View
|
||||
|
||||
|
@ -44,6 +44,8 @@ From the official documentation site:
|
|||
|
||||
> Reducers are just pure functions that take the previous state and an action, and return the next state. Remember to return new state objects, instead of mutating the previous state.
|
||||
|
||||
**Mental Model**: think of Reducer as part of the store and should have no side effects outside of defining how data can change from one state to next given action messages.
|
||||
|
||||
# Exercise
|
||||
|
||||
1. First, take a look at the store interface in the `exercise/src/store/index.tsx` - note that the `Store` interface has two keys: `todos` and `filter`. We'll concentrate on the `todos` which is an object where the keys are IDs and the values are of an `TodoItem` type.
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,15 +1,9 @@
|
|||
import { reducer } from './reducers';
|
||||
import { createStore, compose } from 'redux';
|
||||
import { createStore } from 'redux';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
import { actions } from './actions';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore) {
|
||||
return createStore(reducer, initialStore, composeEnhancers());
|
||||
}
|
||||
|
||||
const store = createStoreWithDevTool(reducer, {});
|
||||
const store = createStore(reducer, {}, composeWithDevTools());
|
||||
|
||||
console.log(store.getState());
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,19 +1,18 @@
|
|||
import { reducer } from './reducers';
|
||||
import { createStore, compose } from 'redux';
|
||||
import { createStore } from 'redux';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
import { actions } from './actions';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore) {
|
||||
return createStore(reducer, initialStore, composeEnhancers());
|
||||
}
|
||||
|
||||
const store = createStoreWithDevTool(reducer, {});
|
||||
const store = createStore(reducer, {}, composeWithDevTools());
|
||||
|
||||
console.log(store.getState());
|
||||
|
||||
store.dispatch(actions.addTodo('hello'));
|
||||
store.dispatch(actions.addTodo('world'));
|
||||
/*
|
||||
TODO: dispatch several actions and see the effect to the state inside the Redux devtool
|
||||
|
||||
store.dispatch(actions.???);
|
||||
store.dispatch(actions.???);
|
||||
store.dispatch(actions.???);
|
||||
*/
|
||||
|
||||
console.log(store.getState());
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,20 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { reducer } from './reducers';
|
||||
import { createStore, compose } from 'redux';
|
||||
import { createStore } from 'redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TodoApp } from './components/TodoApp';
|
||||
import { actions } from './actions';
|
||||
import { initializeIcons } from '@uifabric/icons';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore) {
|
||||
return createStore(reducer, initialStore, composeEnhancers());
|
||||
}
|
||||
|
||||
const store = createStoreWithDevTool(reducer, {});
|
||||
const store = createStore(reducer, {}, composeWithDevTools());
|
||||
|
||||
store.dispatch(actions.addTodo('hello'));
|
||||
store.dispatch(actions.addTodo('world'));
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,20 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { reducer } from './reducers';
|
||||
import { createStore, compose } from 'redux';
|
||||
import { createStore } from 'redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TodoApp } from './components/TodoApp';
|
||||
import { actions } from './actions';
|
||||
import { initializeIcons } from '@uifabric/icons';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore) {
|
||||
return createStore(reducer, initialStore, composeEnhancers());
|
||||
}
|
||||
|
||||
const store = createStoreWithDevTool(reducer, {});
|
||||
const store = createStore(reducer, {}, composeWithDevTools());
|
||||
|
||||
store.dispatch(actions.addTodo('hello'));
|
||||
store.dispatch(actions.addTodo('world'));
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,21 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { reducer } from './reducers';
|
||||
import { createStore, compose } from 'redux';
|
||||
import { createStore } from 'redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TodoApp } from './components/TodoApp';
|
||||
import { actions } from './actions';
|
||||
import { initializeIcons } from '@uifabric/icons';
|
||||
import { Store } from './store';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore?: Store) {
|
||||
return createStore(reducer, initialStore, composeEnhancers());
|
||||
}
|
||||
|
||||
const store = createStoreWithDevTool(reducer);
|
||||
const store = createStore(reducer, {}, composeWithDevTools());
|
||||
|
||||
store.dispatch(actions.addTodo('hello'));
|
||||
store.dispatch(actions.addTodo('world'));
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,21 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { reducer } from './reducers';
|
||||
import { createStore, compose } from 'redux';
|
||||
import { createStore } from 'redux';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TodoApp } from './components/TodoApp';
|
||||
import { actions } from './actions';
|
||||
import { initializeIcons } from '@uifabric/icons';
|
||||
import { Store } from './store';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore?: Store) {
|
||||
return createStore(reducer, initialStore, composeEnhancers());
|
||||
}
|
||||
|
||||
const store = createStoreWithDevTool(reducer);
|
||||
const store = createStore(reducer, {}, composeWithDevTools());
|
||||
|
||||
store.dispatch(actions.addTodo('hello'));
|
||||
store.dispatch(actions.addTodo('world'));
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,20 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { reducer } from './reducers';
|
||||
import { applyMiddleware, createStore, compose } from 'redux';
|
||||
import { applyMiddleware, createStore } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TodoApp } from './components/TodoApp';
|
||||
import { initializeIcons } from '@uifabric/icons';
|
||||
import { Store, FilterTypes } from './store';
|
||||
import { FilterTypes } from './store';
|
||||
import * as service from './service';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore?: Store) {
|
||||
return createStore(reducer, initialStore, composeEnhancers(applyMiddleware(thunk)));
|
||||
}
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
|
||||
(async () => {
|
||||
const preloadStore = {
|
||||
|
@ -22,7 +16,7 @@ function createStoreWithDevTool(reducer, initialStore?: Store) {
|
|||
filter: 'all' as FilterTypes
|
||||
};
|
||||
|
||||
const store = createStoreWithDevTool(reducer, preloadStore);
|
||||
const store = createStore(reducer, preloadStore, composeWithDevTools(applyMiddleware(thunk)));
|
||||
|
||||
initializeIcons();
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
|
@ -1,20 +1,14 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { reducer } from './reducers';
|
||||
import { applyMiddleware, createStore, compose } from 'redux';
|
||||
import { applyMiddleware, createStore } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
import { Provider } from 'react-redux';
|
||||
import { TodoApp } from './components/TodoApp';
|
||||
import { initializeIcons } from '@uifabric/icons';
|
||||
import { Store, FilterTypes } from './store';
|
||||
import { FilterTypes } from './store';
|
||||
import * as service from './service';
|
||||
|
||||
/* Goop for making the Redux dev tool to work */
|
||||
declare var window: any;
|
||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||
function createStoreWithDevTool(reducer, initialStore?: Store) {
|
||||
return createStore(reducer, initialStore, composeEnhancers(applyMiddleware(thunk)));
|
||||
}
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
|
||||
(async () => {
|
||||
// TODO: to make the store pre-populate with data from the service,
|
||||
|
@ -24,7 +18,7 @@ function createStoreWithDevTool(reducer, initialStore?: Store) {
|
|||
filter: 'all' as FilterTypes
|
||||
};
|
||||
|
||||
const store = createStoreWithDevTool(reducer, preloadStore);
|
||||
const store = createStore(reducer, preloadStore, composeWithDevTools(applyMiddleware(thunk)));
|
||||
|
||||
initializeIcons();
|
||||
|
||||
|
|
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Различия файлов скрыты, потому что одна или несколько строк слишком длинны
Загрузка…
Ссылка в новой задаче