Created
August 29, 2020 12:50
-
-
Save oxyflour/1d7f6ab5268d8d9578f96c9ef59f848f to your computer and use it in GitHub Desktop.
async generator react
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <html> | |
| <body> | |
| <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script> | |
| <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> | |
| <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> | |
| <script src="index.jsx" type="text/babel"></script> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function sleep(t) { | |
| return new Promise(resolve => setTimeout(resolve, t)) | |
| } | |
| async function delayed(x, t = 2000) { | |
| await sleep(t) | |
| return x | |
| } | |
| const createElement = React.createElement.bind(React) | |
| React.createElement = (tag, props, ...children) => ({ tag, props, children }) | |
| function render(elem, container) { | |
| async function show() { | |
| ReactDOM.render(await convert(elem), container) | |
| } | |
| async function convert(elem) { | |
| let { tag, props, children } = elem | |
| if (typeof tag === 'string') { | |
| children = await Promise.all(children.map(child => convert(child))) | |
| return createElement(tag, props, ...children) | |
| } else if (typeof tag === 'function') { | |
| if (!elem.iter) { | |
| elem.iter = tag(async val => { | |
| elem.next = await elem.iter.next(val) | |
| await show() | |
| }, props, ...children) | |
| elem.next = await elem.iter.next() | |
| } | |
| return await convert(elem.next.done ? elem.ret : (elem.ret = elem.next.value)) | |
| } else if (Array.isArray(elem)) { | |
| return await Promise.all(elem.map(el => convert(el))) | |
| } else { | |
| return elem | |
| } | |
| } | |
| return show() | |
| } | |
| async function *Counter(next, props) { | |
| let count = 1 | |
| while (true) { | |
| count = yield <div key={ props.key }> | |
| <button onClick={ () => next(count + 1) }>+</button> | |
| [ { count } ] | |
| <button onClick={ () => next(count - 1) }>-</button> | |
| </div> | |
| } | |
| } | |
| async function *App(next) { | |
| setTimeout(next) | |
| yield <div>loading...</div> | |
| try { | |
| const arr = await delayed([0, 1]) | |
| yield <div> | |
| { arr.map(val => <Counter key={ val } />) } | |
| <button onClick={ next }>next</button> | |
| </div> | |
| } catch (err) { | |
| yield <div style={{ color: 'red' }}>error { err.message }</div> | |
| } | |
| } | |
| const div = document.createElement('div') | |
| document.body.append(div) | |
| render(<App />, div) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment