Gathering detailed insights and metrics for chizu
Gathering detailed insights and metrics for chizu
Gathering detailed insights and metrics for chizu
Gathering detailed insights and metrics for chizu
mizuharachizuru
提供了格式化时间、HTMLEscape相关功能
chizu12
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
@dexou/chizu
testnet tea
@chizukicn/unplugin-generate-component-name
A plugin for auto generate vue component name.
npm install chizu
Typescript
Module System
Node Version
NPM Version
70.6
Supply Chain
98
Quality
94.3
Maintenance
100
Vulnerability
99.3
License
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
5
35
Strongly typed React framework using generators and efficiently updated views alongside the publish-subscribe pattern.
Actions are responsible for mutating the state of the view. In the below example the name
is dispatched from the view to the actions, the state is updated and the view is rendered with the updated value.
1export default <Actions<Module>>function Actions(module) { 2 return { 3 [Action.Name](name) { 4 return module.actions.produce((draft) => { 5 draft.name = name; 6 }); 7 }, 8 }; 9};
1export default function Profile(props: Props): React.ReactElement { 2 return ( 3 <Scope<Module> using={{ model, actions, props }}> 4 {(module) => ( 5 <> 6 <p>Hey {module.model.name}</p> 7 8 <button 9 onClick={() => module.actions.dispatch([Action.Name, randomName()])} 10 > 11 Switch profile 12 </button> 13 </> 14 )} 15 </Scope> 16 ); 17}
You can perform asynchronous operations in the action which will cause the associated view to render a second time:
1export default <Actions<Module>>function Actions(module) { 2 return { 3 async *[Action.Name]() { 4 yield module.actions.produce((draft) => { 5 draft.name = null; 6 }); 7 8 const name = await fetch(/* ... */); 9 10 return module.actions.produce((draft) => { 11 draft.name = name; 12 }); 13 }, 14 }; 15};
1export default function Profile(props: Props): React.ReactElement { 2 return ( 3 <Scope<Module> using={{ model, actions, props }}> 4 {(module) => ( 5 <> 6 <p>Hey {module.model.name}</p> 7 8 <button onClick={() => module.actions.dispatch([Action.Name])}> 9 Switch profile 10 </button> 11 </> 12 )} 13 </Scope> 14 ); 15}
However in the above example where the name is fetched asynchronously, there is no feedback to the user – we can improve that significantly by using the module.actions.annotate
and module.validate
helpers:
1export default <Actions<Module>>function Actions(module) { 2 return { 3 async *[Action.Name]() { 4 yield module.actions.produce((draft) => { 5 draft.name = module.actions.annotate(null); 6 }); 7 8 const name = await fetch(/* ... */); 9 return module.actions.produce((draft) => { 10 draft.name = name; 11 }); 12 }, 13 }; 14};
1export default function ProfileView(props: Props): React.ReactElement { 2 return ( 3 <Scope<Module> using={{ module, actions, props }}> 4 {(module) => ( 5 <> 6 <p>Hey {module.model.name}</p> 7 8 {module.validate.name.pending() && <p>Switching profiles…</p>} 9 10 <button 11 disabled={module.validate.name.is(State.Op.Update)} 12 onClick={() => module.actions.dispatch([Action.Name])} 13 > 14 Switch profile 15 </button> 16 </> 17 )} 18 </Scope> 19 ); 20}
Most errors are likely to occur in the actions because the views should be free of side effects. First and foremost it's recommended that errors be encoded into your corresponding module using a library such as [neverthrow
[(https://github.com/supermacro/neverthrow)] – that way you can effectively identify which properties are fallible and render the DOM accordingly:
1export default <Actions<Module>>function Actions(module) { 2 return { 3 *[Action.Name]() { 4 yield module.actions.produce((draft) => { 5 draft.name = null; 6 }); 7 8 const name = await fetch(/* ... */); 9 10 return module.actions.produce((draft) => { 11 draft.name = name ? Result.Just(name) : Result.Nothing(); 12 }); 13 }, 14 }; 15};
However in eventualities where an error has not been caught in an action then the Lifecycle.Error
is the next best thing – use it to display a toast message and log it your chosen error log service.
Additionally when rendering an error may be thrown which prevents the DOM from updating as you'd expect – perhaps a side effect has delivered an unexpected data structure. In those cases again Lifecycle.Error
is your friend. When such an error is thrown the component boundary will be switched to Boundary.Error
which you detect using module.boundary.is(Boundary.Error)
and switch to an alternative markup that should render, within that you could display a button to attempt recovery – simply call an action again and update the meta to switch the boundary back to Boundary.Default
:
1export default <Actions<Module>>function Actions(module) { 2 return { 3 *[Action.Recover]() { 4 yield module.actions.produce((draft) => { 5 draft.name = null; 6 }); 7 8 const name = await fetch(/* ... */); 9 10 return module.actions.produce((draft, meta) => { 11 meta.boundary = Boundary.Default; 12 draft.name = name; 13 }); 14 }, 15 }; 16};
If the component again throws an error after attempting recovery, it will simply switch back to the Boundary.Error
again.
Actions can communicate with other mounted actions using the DistributedActions
approach. You can configure the enum and union type in the root of your application:
1export enum DistributedAction { 2 SignedOut = "distributed/signed-out", 3} 4 5export type DistributedActions = [DistributedAction.SignedOut];
Note that you must prefix the enum name with distributed
for it to behave as a distributed event, otherwise it'll be considered a module event only. Once you have the distributed actions you simply need to augment the module actions union with the DistributedActions
and use it as you do other actions:
1export type Actions = DistributedActions | [Action.Task, string]; // etc...
In the eventuality that you have a component but don't want associated actions, models, etc… but want to still fire actions either the closest module or a distributed action, you can use the useScoped
hook:
1const module = useScoped<Module>(); 2 3// ... 4 5module.actions.dispatch([Action.Task, "My task that needs to be done."]);
Alternatively you can pass the current module as a prop to your components using the Scoped
helper:
1export type Props = { 2 module: Scoped<Module>; 3};
In many cases you'll still want to retrieve contextual values from within actions – which you can do by using the module.actions.context
function:
1export default <Actions<Module>>function Actions(module) { 2 const context = module.actions.context({ 3 name: NameContext 4 }); 5 6 return { 7 [Action.Name](name) { 8 return module.actions.produce((draft) => { 9 draft.name = context.name; 10 }); 11 }, 12 }; 13};
If you need the context values to be reactive and fire the Lifecycle.Derive
method then simply add it to your props
definition when you initialise your scoped component:
1export default function Profile(props: Props): React.ReactElement { 2 const name = React.useContext(NameContext); 3 4 return ( 5 <Scope<Module> using={{ model, actions, props: { ...props, name } }}> 6 {(module) => ( 7 <> 8 <p>Hey {module.model.name}</p> 9 10 <button 11 onClick={() => module.actions.dispatch([Action.Name, randomName()])} 12 > 13 Switch profile 14 </button> 15 </> 16 )} 17 </Scope> 18 ); 19}
No vulnerabilities found.
No security vulnerabilities found.