({ data: [] }, namespace)
21 | .subscript(({ dispatch }) => {
22 | dispatch(fetchTodos());
23 | })
24 | .case(saveTodos, (state, payload) => {
25 | return {
26 | data: payload,
27 | };
28 | })
29 | .takeEvery(addTodo, function *(payload, { call, put }) {
30 | yield call(services.addTodo, payload);
31 | yield put(fetchTodos);
32 | })
33 | .takeEvery(fetchTodos, function *(payload, { call, put }) {
34 | const todos = yield call(services.fetchTodo);
35 | yield put(saveTodos(todos));
36 | })
37 | .build();
38 |
39 | export default model;
40 |
--------------------------------------------------------------------------------
/dva-model-creator/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "dva-model-creator": "^0.4.3",
4 | "react": "^16.11.0"
5 | },
6 | "devDependencies": {
7 | "@types/react": "^16.9.11",
8 | "umi-plugin-react": "^1.12.8",
9 | "umi-types": "^0.5.3",
10 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/dva-model-creator/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #F2C679;
4 | }
5 |
--------------------------------------------------------------------------------
/dva-model-creator/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { connect } from 'dva';
3 | import { Todos, fetchTodos, addTodo } from '../models/todos';
4 | import styles from './index.css';
5 |
6 | function mapStateToProps(state: { todos: Todos }) {
7 | return {
8 | todos: state.todos,
9 | };
10 | }
11 |
12 | export default connect(mapStateToProps)(function(props) {
13 | const [value, setValue] = useState('');
14 | return (
15 |
16 |
Page index
17 | Todos
18 | {
19 | (props.todos as Todos).data.map(({ name, done }) => {
20 | return { name };
21 | })
22 | }
23 |
31 |
32 | );
33 | })
34 |
--------------------------------------------------------------------------------
/dva-model-creator/services/todos.ts:
--------------------------------------------------------------------------------
1 |
2 | export async function addTodo(text: string) {
3 | await fetch(`/api/todos/add?text=${text}`);
4 | }
5 |
6 | export async function fetchTodo() {
7 | const res = await fetch(`/api/todos`);
8 | const ret = await res.json();
9 | return ret;
10 | }
11 |
--------------------------------------------------------------------------------
/dva-model-creator/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "build/dist",
4 | "module": "esnext",
5 | "target": "esnext",
6 | "lib": ["esnext", "dom"],
7 | "sourceMap": true,
8 | "baseUrl": ".",
9 | "jsx": "react",
10 | "allowSyntheticDefaultImports": true,
11 | "moduleResolution": "node",
12 | "forceConsistentCasingInFileNames": true,
13 | "noImplicitReturns": true,
14 | "suppressImplicitAnyIndexErrors": true,
15 | "noUnusedLocals": true,
16 | "allowJs": true,
17 | "experimentalDecorators": true,
18 | "strict": true,
19 | "paths": {
20 | "@/*": ["./src/*"]
21 | }
22 | },
23 | "exclude": [
24 | "node_modules",
25 | "build",
26 | "scripts",
27 | "acceptance-tests",
28 | "webpack",
29 | "jest",
30 | "src/setupTests.ts",
31 | "tslint:latest",
32 | "tslint-config-prettier"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/dva-model-creator/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.css';
2 |
--------------------------------------------------------------------------------
/hox/.umirc.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | plugins: [
4 | 'umi-plugin-autolayout',
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/hox/README.md:
--------------------------------------------------------------------------------
1 | # hox
2 |
3 | ## Links
4 |
5 | * https://github.com/umijs/hox
6 | * https://zhuanlan.zhihu.com/p/88738712
7 |
--------------------------------------------------------------------------------
/hox/hooks/useCount.js:
--------------------------------------------------------------------------------
1 | import { createModel } from "hox";
2 | import { useState } from 'react';
3 |
4 | function useCount() {
5 | const [count, setState] = useState(0);
6 |
7 | function increment() {
8 | setState(count + 1);
9 | }
10 |
11 | return {
12 | count,
13 | increment,
14 | };
15 | }
16 |
17 | export default createModel(useCount);
18 | export { useCount as useLocalCount };
19 |
--------------------------------------------------------------------------------
/hox/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "hox": "^1.0.0"
4 | },
5 | "devDependencies": {
6 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/hox/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #F2CC79;
4 | }
5 |
--------------------------------------------------------------------------------
/hox/pages/index.js:
--------------------------------------------------------------------------------
1 | import useCount from "../hooks/useCount";
2 | import styles from './index.css';
3 |
4 | export default function() {
5 | const { count, increment } = useCount();
6 | return (
7 |
8 |
Index Page (Global Hook)
9 | Count: {count}
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/hox/pages/users.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #7993F2;
4 | }
5 |
--------------------------------------------------------------------------------
/hox/pages/users.js:
--------------------------------------------------------------------------------
1 |
2 | import styles from './users.css';
3 | import { useLocalCount } from "../hooks/useCount";
4 |
5 | export default function() {
6 | const { count, increment } = useLocalCount();
7 | return (
8 |
9 |
Users Page (Local Hook)
10 | Count: {count}
11 |
12 |
13 | );
14 | }
15 |
--------------------------------------------------------------------------------
/icestore/README.md:
--------------------------------------------------------------------------------
1 | # icestore
2 |
3 | ## Links
4 |
5 | * https://github.com/ice-lab/icestore
6 |
--------------------------------------------------------------------------------
/icestore/mock/todos.js:
--------------------------------------------------------------------------------
1 |
2 | const todos = [
3 | { name: 'react' },
4 | { name: 'vue', done: true },
5 | { name: 'angular' },
6 | ];
7 |
8 | export default {
9 | '/api/todos': todos,
10 | '/api/todos/add': (req, res) => {
11 | todos.push({ name: req.query.text });
12 | return res.json({ success: 1 });
13 | },
14 | '/api/todos/clear': (req, res) => {
15 | todos.splice(2, todos.length);
16 | return res.json({ success: 1 });
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/icestore/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@ice/store": "^0.3.0",
4 | "@ice/store-logger": "^0.1.0"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/icestore/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #7983F2;
4 | }
5 |
--------------------------------------------------------------------------------
/icestore/pages/index.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import stores from '../stores';
3 | import styles from './index.css';
4 |
5 | export default function() {
6 | const {
7 | todos,
8 | addTodo,
9 | fetchTodos,
10 | } = stores.useStore('todos');
11 | const [value, setValue] = useState('');
12 |
13 | useEffect(() => {
14 | fetchTodos();
15 | }, []);
16 |
17 | return (
18 |
19 |
Page index
20 |
todos
21 |
22 | {
23 | todos.map(({ name, done }) => {
24 | return - { name } {done ? 'x' : ''}
25 | })
26 | }
27 |
28 |
36 |
37 | );
38 | }
39 |
--------------------------------------------------------------------------------
/icestore/stores/index.js:
--------------------------------------------------------------------------------
1 | import Icestore from '@ice/store';
2 | import logger from '@ice/store-logger';
3 | import todos from './todos';
4 |
5 | const stores = new Icestore();
6 | stores.applyMiddleware([
7 | logger,
8 | ]);
9 | stores.registerStore('todos', todos);
10 |
11 | export default stores;
12 |
--------------------------------------------------------------------------------
/icestore/stores/todos.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | todos: [
4 | ],
5 | async fetchTodos() {
6 | const todos = await fetch(`/api/todos`)
7 | .then(x => x.json());
8 | this.todos = todos;
9 | },
10 | async addTodo(todo) {
11 | await fetch(`/api/todos/add?text=${todo}`);
12 | },
13 | };
14 |
--------------------------------------------------------------------------------
/neeko/.umirc.ts:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: ['umi-plugin-autolayout'],
3 | };
4 |
5 |
--------------------------------------------------------------------------------
/neeko/README.md:
--------------------------------------------------------------------------------
1 | # neeko(阿里内部)
2 |
3 | ## Links
4 |
5 | * https://yuque.antfin-inc.com/kot/neeko
6 |
--------------------------------------------------------------------------------
/neeko/mock/todos.ts:
--------------------------------------------------------------------------------
1 |
2 | const todos = [
3 | { name: 'react' },
4 | { name: 'vue', done: true },
5 | { name: 'angular' },
6 | ];
7 |
8 | export default {
9 | '/api/todos': todos,
10 | '/api/todos/add': (req, res) => {
11 | todos.push({ name: req.query.text });
12 | return res.json({ success: 1 });
13 | },
14 | '/api/todos/clear': (req, res) => {
15 | todos.splice(2, todos.length);
16 | return res.json({ success: 1 });
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/neeko/models/todos.ts:
--------------------------------------------------------------------------------
1 | import { model } from '@alipay/xmas-neeko';
2 |
3 | interface ITodo {
4 | name: string;
5 | }
6 |
7 | export default model({
8 | state: {
9 | todos: [] as ITodo[],
10 | },
11 | computed: {
12 | length(): number {
13 | return this.todos.length;
14 | },
15 | },
16 | effects: {
17 | async addTodo(name: string) {
18 | await fetch(`/api/todos/add?text=${name}`);
19 | },
20 | async fetchTodos() {
21 | const res = await fetch(`/api/todos`);
22 | const todos = await res.json();
23 | this.update({
24 | todos,
25 | });
26 | },
27 | },
28 | hooks: {
29 | init() {
30 | this.fetchTodos();
31 | },
32 | }
33 | });
34 |
--------------------------------------------------------------------------------
/neeko/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@alipay/xmas-neeko": "^0.3.3"
4 | },
5 | "devDependencies": {
6 | "@types/react": "^16.9.11",
7 | "react": "^16.11.0",
8 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/neeko/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #F279E0;
4 | }
5 |
--------------------------------------------------------------------------------
/neeko/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { observer } from '@alipay/xmas-neeko/react';
3 | import styles from './index.css';
4 | import todos from '../models/todos';
5 |
6 | export default observer(function() {
7 | const [value, setValue] = useState('');
8 |
9 | return (
10 |
11 |
Page index
12 |
Totally {todos.length} todos.
13 | {
14 | todos.todos.map(todo =>
{ todo.name })
15 | }
16 |
24 |
25 | );
26 | })
27 |
--------------------------------------------------------------------------------
/neeko/pages/users.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #C079F2;
4 | }
5 |
--------------------------------------------------------------------------------
/neeko/pages/users.tsx:
--------------------------------------------------------------------------------
1 |
2 | import React from 'react';
3 |
4 | import styles from './users.css';
5 |
6 | export default function() {
7 | return (
8 |
9 |
Page users
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/neeko/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "build/dist",
4 | "module": "esnext",
5 | "target": "esnext",
6 | "lib": ["esnext", "dom"],
7 | "sourceMap": true,
8 | "baseUrl": ".",
9 | "jsx": "react",
10 | "allowSyntheticDefaultImports": true,
11 | "moduleResolution": "node",
12 | "forceConsistentCasingInFileNames": true,
13 | "noImplicitReturns": true,
14 | "suppressImplicitAnyIndexErrors": true,
15 | "noUnusedLocals": true,
16 | "allowJs": true,
17 | "experimentalDecorators": true,
18 | "strict": true,
19 | "paths": {
20 | "@/*": ["./src/*"]
21 | }
22 | },
23 | "exclude": [
24 | "node_modules",
25 | "build",
26 | "scripts",
27 | "acceptance-tests",
28 | "webpack",
29 | "jest",
30 | "src/setupTests.ts",
31 | "tslint:latest",
32 | "tslint-config-prettier"
33 | ]
34 | }
35 |
--------------------------------------------------------------------------------
/neeko/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.css';
2 |
--------------------------------------------------------------------------------
/plugin-model/.umirc.ts:
--------------------------------------------------------------------------------
1 | import { IConfig } from 'umi-types';
2 |
3 | export default {
4 | plugins: [
5 | 'umi-plugin-autolayout',
6 | '@umijs/plugin-model',
7 | '@umijs/plugin-initial-state',
8 | ],
9 | } as IConfig;
10 |
--------------------------------------------------------------------------------
/plugin-model/README.md:
--------------------------------------------------------------------------------
1 | # @umijs/plugin-model
2 |
3 | ## Links
4 |
5 | * https://github.com/umijs/plugin-model
6 |
--------------------------------------------------------------------------------
/plugin-model/app.ts:
--------------------------------------------------------------------------------
1 |
2 | export async function getInitialState() {
3 | return 'Hello world';
4 | }
5 |
--------------------------------------------------------------------------------
/plugin-model/mock/todos.js:
--------------------------------------------------------------------------------
1 |
2 | const todos = [
3 | { name: 'react' },
4 | { name: 'vue', done: true },
5 | { name: 'angular' },
6 | ];
7 |
8 | export default {
9 | '/api/todos': todos,
10 | '/api/todos/add': (req, res) => {
11 | todos.push({ name: req.query.text });
12 | return res.json({ success: 1 });
13 | },
14 | '/api/todos/clear': (req, res) => {
15 | todos.splice(2, todos.length);
16 | return res.json({ success: 1 });
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/plugin-model/models/count.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import { useModel } from 'umi';
3 |
4 | export default function () {
5 | const [ count, setCount ] = useState(0);
6 | const { todos } = useModel('todos');
7 |
8 | useEffect(() => {
9 | setCount(todos.length);
10 | }, [todos]);
11 |
12 | return {
13 | count,
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/plugin-model/models/todos.ts:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from 'react';
2 | import * as todoService from '@/services/todos';
3 |
4 | export default function () {
5 | const [todos, setTodos] = useState([]);
6 |
7 | async function fetchTodos() {
8 | const todos = await todoService.fetchTodo();
9 | setTodos(todos);
10 | }
11 |
12 | async function addTodo(text: string) {
13 | await todoService.addTodo(text);
14 | await fetchTodos();
15 | }
16 |
17 | useEffect(() => {
18 | (async () => {
19 | await fetchTodos();
20 | })();
21 | }, []);
22 |
23 | return {
24 | todos,
25 | addTodo,
26 | fetchTodos,
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/plugin-model/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "scripts": {
3 | "start": "umi dev"
4 | },
5 | "devDependencies": {
6 | "@types/react": "^16.9.11",
7 | "@umijs/plugin-model": "^0.1.0",
8 | "@umijs/plugin-initial-state": "^0.1.0",
9 | "umi-types": "^0.5.3",
10 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/plugin-model/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #79CCF2;
4 | }
5 |
--------------------------------------------------------------------------------
/plugin-model/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useModel } from 'umi';
3 | import styles from './index.css';
4 |
5 | export default function() {
6 | const [value, setValue] = useState('');
7 | const { todos, addTodo, fetchTodos } = useModel('todos');
8 | const { count } = useModel('count');
9 | const { initialState } = useModel('@@initialState');
10 | return (
11 |
12 |
Page index
13 | Test {initialState || ''}
14 | Todos ({count})
15 | {
16 | todos.map(({ name, done }) => {
17 | return { name };
18 | })
19 | }
20 |
28 |
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/plugin-model/services/todos.ts:
--------------------------------------------------------------------------------
1 |
2 | export async function addTodo(text: string) {
3 | await fetch(`/api/todos/add?text=${text}`);
4 | }
5 |
6 | export async function fetchTodo() {
7 | const res = await fetch(`/api/todos`);
8 | const ret = await res.json();
9 | return ret;
10 | }
11 |
--------------------------------------------------------------------------------
/plugin-model/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "outDir": "build/dist",
4 | "module": "esnext",
5 | "target": "esnext",
6 | "lib": ["esnext", "dom"],
7 | "sourceMap": true,
8 | "baseUrl": ".",
9 | "jsx": "react",
10 | "allowSyntheticDefaultImports": true,
11 | "moduleResolution": "node",
12 | "forceConsistentCasingInFileNames": true,
13 | "noImplicitReturns": true,
14 | "suppressImplicitAnyIndexErrors": true,
15 | "noUnusedLocals": true,
16 | "allowJs": true,
17 | "experimentalDecorators": true,
18 | "strict": true,
19 | "paths": {
20 | "@/*": ["./*"],
21 | "@@/*": ["./pages/.umi/*"]
22 | }
23 | },
24 | "exclude": [
25 | "node_modules",
26 | "build",
27 | "scripts",
28 | "acceptance-tests",
29 | "webpack",
30 | "jest",
31 | "src/setupTests.ts",
32 | "tslint:latest",
33 | "tslint-config-prettier"
34 | ]
35 | }
36 |
--------------------------------------------------------------------------------
/plugin-model/typings.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.css';
2 |
--------------------------------------------------------------------------------
/react-suspense/app.js:
--------------------------------------------------------------------------------
1 | import ReactDOM from 'react-dom';
2 | import React from 'react';
3 |
4 | export function render() {
5 | ReactDOM.createRoot(document.getElementById('root')).render(
6 | React.createElement(require('@tmp/router').default),
7 | );
8 | }
9 |
--------------------------------------------------------------------------------
/react-suspense/components/ErrorBoundary.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class ErrorBoundary extends React.Component {
4 | state = {
5 | hasError: false, error: null
6 | }
7 |
8 | static getDerivedStateFromError(error) {
9 | return {
10 | hasError: true,
11 | error,
12 | };
13 | }
14 |
15 | render() {
16 | if (this.state.hasError) {
17 | return Something error: {this.state.error.message}
18 | }
19 |
20 | return this.props.children;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/react-suspense/components/Num.js:
--------------------------------------------------------------------------------
1 |
2 | export default function Num(props) {
3 | const num = props.resource.num.read();
4 | return (
5 |
6 | Number: {num}
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/react-suspense/components/Person.js:
--------------------------------------------------------------------------------
1 |
2 | export default function Person(props) {
3 | const person = props.resource.person.read();
4 | return (
5 |
6 | name: {person.name.first}
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/react-suspense/createResource.js:
--------------------------------------------------------------------------------
1 | import wrapPromise from "./wrapPromise";
2 |
3 | function fetchPerson() {
4 | return fetch('https://randomuser.me/api')
5 | .then(x => x.json())
6 | .then(x => x.results[0]);
7 | }
8 |
9 | function getNum() {
10 | return new Promise(resolve => {
11 | setTimeout(() => {
12 | resolve(Math.random());
13 | }, 1000);
14 | });
15 | }
16 |
17 | export default function createResource() {
18 | return {
19 | person: wrapPromise(fetchPerson()),
20 | num: wrapPromise(getNum()),
21 | };
22 | }
23 |
--------------------------------------------------------------------------------
/react-suspense/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "react": "^0.0.0-experimental-f6b8d31a7",
4 | "react-dom": "^0.0.0-experimental-f6b8d31a7"
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/react-suspense/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #797BF2;
4 | }
5 |
--------------------------------------------------------------------------------
/react-suspense/pages/index.js:
--------------------------------------------------------------------------------
1 | import { Suspense, useState, useTransition } from 'react';
2 | import styles from './index.css';
3 | import createResource from "../createResource";
4 | import Person from "../components/Person";
5 | import Num from "../components/Num";
6 | import ErrorBoundary from "../components/ErrorBoundary";
7 |
8 | const initialResource = createResource();
9 |
10 | export default function() {
11 | const [resource, setResource] = useState(initialResource);
12 | const [startTransition, isPending] = useTransition({
13 | timeoutMs: 1000,
14 | });
15 |
16 | return (
17 |
18 |
Page index
19 |
20 | loading...}>
21 |
22 |
23 | loading...}>
24 |
25 |
26 |
27 |
32 |
33 | );
34 | }
35 |
--------------------------------------------------------------------------------
/react-suspense/wrapPromise.js:
--------------------------------------------------------------------------------
1 |
2 | export default function wrapPromise(promise) {
3 | let status = 'pending';
4 | let result = '';
5 | let suspender = promise.then(r => {
6 | status = 'success';
7 | result = r;
8 | }, e => {
9 | status = 'error';
10 | result = e;
11 | });
12 |
13 | return {
14 | read() {
15 | if (status === 'pending') {
16 | throw suspender;
17 | } else if (status === 'error') {
18 | throw result;
19 | }
20 | return result;
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/swr/.umirc.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: ['umi-plugin-autolayout'],
3 | };
4 |
5 |
--------------------------------------------------------------------------------
/swr/README.md:
--------------------------------------------------------------------------------
1 | # swr
2 |
3 | ## Links
4 |
5 | * https://swr.now.sh/
6 | * https://github.com/zeit/swr
7 |
8 |
--------------------------------------------------------------------------------
/swr/auth.js:
--------------------------------------------------------------------------------
1 |
2 | export function login() {
3 | document.cookie = 'swr-test-token=swr;'
4 | }
5 |
6 | export function logout() {
7 | document.cookie = 'swr-test-token=; expires=Thu, 01 Jan 1970 00:00:01 GMT;'
8 | }
9 |
--------------------------------------------------------------------------------
/swr/fetch.js:
--------------------------------------------------------------------------------
1 |
2 | export default async (...args) => {
3 | const res = await fetch(...args);
4 | return await res.json();
5 | }
6 |
--------------------------------------------------------------------------------
/swr/hooks/useGlobalState.js:
--------------------------------------------------------------------------------
1 | import useSWR from 'swr';
2 |
3 | let state = {
4 | name: 'sorrycc',
5 | };
6 |
7 | export default function () {
8 | const { data, revalidate } = useSWR('globalState', () => Promise.resolve(state), {
9 | revalidateOnFocus: false,
10 | });
11 | return {
12 | data,
13 | setData(newData) {
14 | state = {
15 | ...data,
16 | ...newData,
17 | };
18 | revalidate();
19 | },
20 | };
21 | }
22 |
--------------------------------------------------------------------------------
/swr/hooks/useTodos.js:
--------------------------------------------------------------------------------
1 | import useSWR from 'swr';
2 | import fetch from '../fetch';
3 |
4 | export default function () {
5 | return useSWR(`/api/todos`, fetch);
6 | }
7 |
--------------------------------------------------------------------------------
/swr/hooks/useUsers.js:
--------------------------------------------------------------------------------
1 | import useSWR from 'swr';
2 | import { useState } from 'react';
3 | import fetch from '../fetch';
4 |
5 | export default function (initPage) {
6 | const [page, setPage] = useState(initPage);
7 | const { data } = useSWR(`/api/users?page=${page}`, fetch, {
8 | revalidateOnFocus: false,
9 | });
10 | return {
11 | data,
12 | page,
13 | setPage,
14 | };
15 | }
16 |
--------------------------------------------------------------------------------
/swr/layouts/index.js:
--------------------------------------------------------------------------------
1 | import useSWR from "swr";
2 | import { Link, router } from 'umi';
3 | import fetch from '../fetch';
4 | import {login, logout} from "../auth";
5 |
6 | export default function (props) {
7 | const { data, revalidate } = useSWR('/api/login', fetch);
8 | if (!data) return loading...
;
9 | if (data.loggedIn) {
10 | return (
11 |
12 |
Welcome, { data.name }
13 |

14 |
18 | { props.children }
19 |
20 | );
21 | } else {
22 | return (
23 |
24 |
Please login
25 |
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/swr/mock/index.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | '/api/readers': (req, res) => {
4 | setTimeout(() => {
5 | res.json([
6 | { id: 1, name: 'sorrycc', },
7 | { id: 2, name: 'pigcan', },
8 | ]);
9 | }, 1000);
10 | },
11 | '/api/status': (req, res) => {
12 | setTimeout(() => {
13 | res.json({
14 | messageCount: 5,
15 | });
16 | }, 2000);
17 | },
18 | '/api/count': (req, res) => {
19 | setTimeout(() => {
20 | res.json({
21 | count: parseInt(req.query.count, 10) + 5,
22 | });
23 | }, 1000);
24 | },
25 | }
26 |
--------------------------------------------------------------------------------
/swr/mock/login.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | '/api/login': (req, res) => {
4 | // ref: http://github.com/zeit/swr/tree/master/examples/focus-revalidate/pages/api/user.js
5 | if (req.headers.cookie && req.headers.cookie.includes('swr-test-token=swr')) {
6 | // authorized
7 | res.json({
8 | loggedIn: true,
9 | name: 'ChenCheng',
10 | avatar: 'https://github.com/sorrycc.png'
11 | })
12 | return
13 | }
14 | res.json({
15 | loggedIn: false
16 | })
17 | },
18 | }
19 |
--------------------------------------------------------------------------------
/swr/mock/todos.js:
--------------------------------------------------------------------------------
1 |
2 | const todos = [
3 | 'Learn swr',
4 | 'Buy Airpod Pro',
5 | ];
6 |
7 | export default {
8 | '/api/todos': todos,
9 | '/api/todos/add': (req, res) => {
10 | todos.push(req.query.text);
11 | return res.json({ success: 1 });
12 | },
13 | '/api/todos/clear': (req, res) => {
14 | todos.splice(2, todos.length);
15 | return res.json({ success: 1 });
16 | },
17 | }
18 |
--------------------------------------------------------------------------------
/swr/mock/users.js:
--------------------------------------------------------------------------------
1 |
2 | const users = [
3 | {
4 | "id": 1,
5 | "name": "Leanne Graham",
6 | "username": "Bret",
7 | "email": "Sincere@april.biz",
8 | "address": {
9 | "street": "Kulas Light",
10 | "suite": "Apt. 556",
11 | "city": "Gwenborough",
12 | "zipcode": "92998-3874",
13 | "geo": {
14 | "lat": "-37.3159",
15 | "lng": "81.1496"
16 | }
17 | },
18 | "phone": "1-770-736-8031 x56442",
19 | "website": "hildegard.org",
20 | "company": {
21 | "name": "Romaguera-Crona",
22 | "catchPhrase": "Multi-layered client-server neural-net",
23 | "bs": "harness real-time e-markets"
24 | }
25 | },
26 | {
27 | "id": 2,
28 | "name": "Ervin Howell",
29 | "username": "Antonette",
30 | "email": "Shanna@melissa.tv",
31 | "address": {
32 | "street": "Victor Plains",
33 | "suite": "Suite 879",
34 | "city": "Wisokyburgh",
35 | "zipcode": "90566-7771",
36 | "geo": {
37 | "lat": "-43.9509",
38 | "lng": "-34.4618"
39 | }
40 | },
41 | "phone": "010-692-6593 x09125",
42 | "website": "anastasia.net",
43 | "company": {
44 | "name": "Deckow-Crist",
45 | "catchPhrase": "Proactive didactic contingency",
46 | "bs": "synergize scalable supply-chains"
47 | }
48 | },
49 | {
50 | "id": 3,
51 | "name": "Clementine Bauch",
52 | "username": "Samantha",
53 | "email": "Nathan@yesenia.net",
54 | "address": {
55 | "street": "Douglas Extension",
56 | "suite": "Suite 847",
57 | "city": "McKenziehaven",
58 | "zipcode": "59590-4157",
59 | "geo": {
60 | "lat": "-68.6102",
61 | "lng": "-47.0653"
62 | }
63 | },
64 | "phone": "1-463-123-4447",
65 | "website": "ramiro.info",
66 | "company": {
67 | "name": "Romaguera-Jacobson",
68 | "catchPhrase": "Face to face bifurcated interface",
69 | "bs": "e-enable strategic applications"
70 | }
71 | },
72 | {
73 | "id": 4,
74 | "name": "Patricia Lebsack",
75 | "username": "Karianne",
76 | "email": "Julianne.OConner@kory.org",
77 | "address": {
78 | "street": "Hoeger Mall",
79 | "suite": "Apt. 692",
80 | "city": "South Elvis",
81 | "zipcode": "53919-4257",
82 | "geo": {
83 | "lat": "29.4572",
84 | "lng": "-164.2990"
85 | }
86 | },
87 | "phone": "493-170-9623 x156",
88 | "website": "kale.biz",
89 | "company": {
90 | "name": "Robel-Corkery",
91 | "catchPhrase": "Multi-tiered zero tolerance productivity",
92 | "bs": "transition cutting-edge web services"
93 | }
94 | },
95 | {
96 | "id": 5,
97 | "name": "Chelsey Dietrich",
98 | "username": "Kamren",
99 | "email": "Lucio_Hettinger@annie.ca",
100 | "address": {
101 | "street": "Skiles Walks",
102 | "suite": "Suite 351",
103 | "city": "Roscoeview",
104 | "zipcode": "33263",
105 | "geo": {
106 | "lat": "-31.8129",
107 | "lng": "62.5342"
108 | }
109 | },
110 | "phone": "(254)954-1289",
111 | "website": "demarco.info",
112 | "company": {
113 | "name": "Keebler LLC",
114 | "catchPhrase": "User-centric fault-tolerant solution",
115 | "bs": "revolutionize end-to-end systems"
116 | }
117 | },
118 | {
119 | "id": 6,
120 | "name": "Mrs. Dennis Schulist",
121 | "username": "Leopoldo_Corkery",
122 | "email": "Karley_Dach@jasper.info",
123 | "address": {
124 | "street": "Norberto Crossing",
125 | "suite": "Apt. 950",
126 | "city": "South Christy",
127 | "zipcode": "23505-1337",
128 | "geo": {
129 | "lat": "-71.4197",
130 | "lng": "71.7478"
131 | }
132 | },
133 | "phone": "1-477-935-8478 x6430",
134 | "website": "ola.org",
135 | "company": {
136 | "name": "Considine-Lockman",
137 | "catchPhrase": "Synchronised bottom-line interface",
138 | "bs": "e-enable innovative applications"
139 | }
140 | },
141 | {
142 | "id": 7,
143 | "name": "Kurtis Weissnat",
144 | "username": "Elwyn.Skiles",
145 | "email": "Telly.Hoeger@billy.biz",
146 | "address": {
147 | "street": "Rex Trail",
148 | "suite": "Suite 280",
149 | "city": "Howemouth",
150 | "zipcode": "58804-1099",
151 | "geo": {
152 | "lat": "24.8918",
153 | "lng": "21.8984"
154 | }
155 | },
156 | "phone": "210.067.6132",
157 | "website": "elvis.io",
158 | "company": {
159 | "name": "Johns Group",
160 | "catchPhrase": "Configurable multimedia task-force",
161 | "bs": "generate enterprise e-tailers"
162 | }
163 | },
164 | {
165 | "id": 8,
166 | "name": "Nicholas Runolfsdottir V",
167 | "username": "Maxime_Nienow",
168 | "email": "Sherwood@rosamond.me",
169 | "address": {
170 | "street": "Ellsworth Summit",
171 | "suite": "Suite 729",
172 | "city": "Aliyaview",
173 | "zipcode": "45169",
174 | "geo": {
175 | "lat": "-14.3990",
176 | "lng": "-120.7677"
177 | }
178 | },
179 | "phone": "586.493.6943 x140",
180 | "website": "jacynthe.com",
181 | "company": {
182 | "name": "Abernathy Group",
183 | "catchPhrase": "Implemented secondary concept",
184 | "bs": "e-enable extensible e-tailers"
185 | }
186 | },
187 | {
188 | "id": 9,
189 | "name": "Glenna Reichert",
190 | "username": "Delphine",
191 | "email": "Chaim_McDermott@dana.io",
192 | "address": {
193 | "street": "Dayna Park",
194 | "suite": "Suite 449",
195 | "city": "Bartholomebury",
196 | "zipcode": "76495-3109",
197 | "geo": {
198 | "lat": "24.6463",
199 | "lng": "-168.8889"
200 | }
201 | },
202 | "phone": "(775)976-6794 x41206",
203 | "website": "conrad.com",
204 | "company": {
205 | "name": "Yost and Sons",
206 | "catchPhrase": "Switchable contextually-based project",
207 | "bs": "aggregate real-time technologies"
208 | }
209 | },
210 | {
211 | "id": 10,
212 | "name": "Clementina DuBuque",
213 | "username": "Moriah.Stanton",
214 | "email": "Rey.Padberg@karina.biz",
215 | "address": {
216 | "street": "Kattie Turnpike",
217 | "suite": "Suite 198",
218 | "city": "Lebsackbury",
219 | "zipcode": "31428-2261",
220 | "geo": {
221 | "lat": "-38.2386",
222 | "lng": "57.2232"
223 | }
224 | },
225 | "phone": "024-648-3804",
226 | "website": "ambrose.net",
227 | "company": {
228 | "name": "Hoeger LLC",
229 | "catchPhrase": "Centralized empowering task-force",
230 | "bs": "target end-to-end models"
231 | }
232 | }
233 | ];
234 |
235 | const PER_PAGE = 3;
236 |
237 | export default {
238 | '/api/users': (req, res) => {
239 | const { page } = req.query;
240 | setTimeout(() => {
241 | res.json({
242 | totalUsers: users.length,
243 | totalPages: Math.ceil(users.length / PER_PAGE),
244 | users: users.slice(PER_PAGE * (page - 1), PER_PAGE * page),
245 | });
246 | }, 500);
247 | },
248 | }
249 |
250 |
--------------------------------------------------------------------------------
/swr/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "swr": "^0.1.6",
4 | "graphql-request": "^1.8.2"
5 | },
6 | "devDependencies": {
7 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/swr/pages/global-state.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #797DF2;
4 | }
5 |
--------------------------------------------------------------------------------
/swr/pages/global-state.js:
--------------------------------------------------------------------------------
1 | import styles from './global-state.css';
2 | import useGlobalState from "../hooks/useGlobalState";
3 |
4 | export default function() {
5 | const { data, setData } = useGlobalState();
6 |
7 | return (
8 |
9 |
Global State
10 | name: { data ? data.name : '' }
11 |
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/swr/pages/graphql.js:
--------------------------------------------------------------------------------
1 | import { request } from 'graphql-request';
2 | import useSWR from "swr";
3 |
4 | const API = 'https://api.graph.cool/simple/v1/movies';
5 |
6 | export default function() {
7 | const { data, error } = useSWR(
8 | `{
9 | Movie(title: "Inception") {
10 | releaseDate
11 | actors {
12 | name
13 | }
14 | }
15 | }`,
16 | query => request(API, query),
17 | );
18 |
19 | return (
20 |
21 |
Graphql
22 | {
23 | data ? (
24 | Movie Release Date: {data.Movie.releaseDate}
25 |
) : 'loading...'
26 | }
27 |
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/swr/pages/index.js:
--------------------------------------------------------------------------------
1 | import useSWR from 'swr';
2 | import fetch from '../fetch';
3 |
4 | export default function() {
5 | const { data: readers, error: readersError } = useSWR('/api/readers', fetch, { revalidateOnFocus: false });
6 | const { data: status, error: statusError } = useSWR('/api/status', fetch, { revalidateOnFocus: false });
7 | const { data: count, error: countError } = useSWR(
8 | () => `/api/count?count=${readers.length}`,
9 | fetch,
10 | { revalidateOnFocus: false },
11 | );
12 |
13 | function renderReaders() {
14 | if (readersError) return failed to load: {readersError.message}
;
15 | if (!readers) return loading...
;
16 | return (
17 |
18 | {
19 | readers.map(({ id, name }) => (
20 | - {name}
21 | ))
22 | }
23 |
24 | );
25 | }
26 |
27 | function renderStatus() {
28 | if (statusError) return failed to load: {statusError.message}
;
29 | if (!status) return loading...
;
30 | return (
31 | { status.messageCount }
32 | );
33 | }
34 |
35 | function renderCount() {
36 | if (countError) return failed to load: {countError.message}
;
37 | if (!count) return loading...
;
38 | return (
39 | { count.count }
40 | );
41 | }
42 |
43 | return (
44 |
45 |
Readers
46 | { renderReaders() }
47 | Status
48 | { renderStatus() }
49 | Count
50 | { renderCount() }
51 |
52 | );
53 | }
54 |
--------------------------------------------------------------------------------
/swr/pages/tab-storage-sync.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #E479F2;
4 | }
5 |
--------------------------------------------------------------------------------
/swr/pages/tab-storage-sync.js:
--------------------------------------------------------------------------------
1 | import useSWR, { mutate } from 'swr';
2 | import storage from "../storage";
3 | import styles from './tab-storage-sync.css';
4 |
5 | export default function() {
6 | const { data = { name: '' } } = useSWR('user-name', storage);
7 |
8 | function handleChange(ev) {
9 | localStorage.setItem(
10 | 'user-name',
11 | JSON.stringify({ name: ev.target.value }),
12 | );
13 | mutate('user-name', { name: ev.target.value });
14 | }
15 |
16 | return (
17 |
18 |
Page tab-storage-sync
19 |
20 |
21 |
22 | );
23 | }
24 |
--------------------------------------------------------------------------------
/swr/pages/todos.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import fetch from "../fetch";
3 | import useTodos from "../hooks/useTodos";
4 |
5 | export default function() {
6 | const { data, revalidate } = useTodos();
7 | const [value, setValue] = useState('');
8 |
9 | return data ? (
10 |
11 |
Todos
12 |
13 | {
14 | data.map(todo => {
15 | return - { todo }
;
16 | })
17 | }
18 |
19 |
27 |
31 |
32 | ) : 'loading...';
33 | }
34 |
--------------------------------------------------------------------------------
/swr/pages/users.js:
--------------------------------------------------------------------------------
1 | import { router } from "umi";
2 | import useUsers from "../hooks/useUsers";
3 |
4 | export default function() {
5 | const { data, page, setPage } = useUsers('1');
6 |
7 | function changePageHandler(currPage) {
8 | setPage(currPage);
9 | }
10 |
11 | function renderPages() {
12 | const ret = [];
13 | let index = 1;
14 | while (index <= data.totalPages) {
15 | ret.push({index});
20 | index += 1;
21 | }
22 | return ret;
23 | }
24 |
25 | return (
26 |
27 |
Users
28 | {
29 | data ? (<>
30 |
31 | {
32 | data.users.map(u => {
33 | return - [{u.id}] { u.name }
;
34 | })
35 | }
36 |
37 |
38 | {
39 | renderPages()
40 | }
41 |
42 | >) : 'loading...'
43 | }
44 |
45 |
48 |
49 | );
50 | }
51 |
--------------------------------------------------------------------------------
/swr/storage.js:
--------------------------------------------------------------------------------
1 |
2 | export default async function (key) {
3 | const value = localStorage.getItem(key);
4 | if (!value) return undefined;
5 | return JSON.parse(value);
6 | }
7 |
--------------------------------------------------------------------------------
/umi-hooks/.umirc.js:
--------------------------------------------------------------------------------
1 |
2 | export default {
3 | plugins: [
4 | 'umi-plugin-autolayout'
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/umi-hooks/README.md:
--------------------------------------------------------------------------------
1 | # @umijs/hooks
2 |
3 | ## Links
4 |
5 | * https://github.com/umijs/hooks
6 |
7 |
--------------------------------------------------------------------------------
/umi-hooks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "@umijs/hooks": "^1.3.1"
4 | },
5 | "devDependencies": {
6 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/umi-hooks/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #95F279;
4 | }
5 |
--------------------------------------------------------------------------------
/umi-hooks/pages/index.js:
--------------------------------------------------------------------------------
1 |
2 | import styles from './index.css';
3 |
4 | export default function() {
5 | return (
6 |
7 |
Page index
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/umi-hooks/pages/use-async.js:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useAsync } from '@umijs/hooks';
3 |
4 | export default function() {
5 | const [ id, setId ] = useState(0);
6 | const { data, loading, run, cancel, error } = useAsync(
7 | () => fetch(`https://randomuser.me/api?id=${id}`).then(r => r.json()),
8 | [id],
9 | );
10 | return (
11 |
12 |
Page use-async
13 |
14 |
15 |
16 |
17 |
18 |
19 | { loading ? 'loading...' : null }
20 | { (!loading && data) ?
{data.results[0].email}
: '' }
21 |
22 |
23 | );
24 | }
25 |
--------------------------------------------------------------------------------
/unstated-next/.umirc.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: ['umi-plugin-autolayout'],
3 | };
4 |
5 |
--------------------------------------------------------------------------------
/unstated-next/README.md:
--------------------------------------------------------------------------------
1 | # unstated-next
2 |
3 | ## Links
4 |
5 | * https://github.com/jamiebuilds/unstated-next
6 |
--------------------------------------------------------------------------------
/unstated-next/containers/Count.js:
--------------------------------------------------------------------------------
1 | import { useState } from 'react';
2 | import { createContainer } from 'unstated-next';
3 |
4 | function useCount(initialState = 0) {
5 | const [count, setState] = useState(initialState);
6 |
7 | function increment() {
8 | setState(count + 1);
9 | }
10 |
11 | function decrement() {
12 | setState(count - 1);
13 | }
14 |
15 | return {
16 | count,
17 | increment,
18 | decrement,
19 | };
20 | }
21 |
22 | export default createContainer(useCount);
23 |
--------------------------------------------------------------------------------
/unstated-next/layouts/index.js:
--------------------------------------------------------------------------------
1 | import Count from "../containers/Count";
2 |
3 | export default function (props) {
4 | return (
5 |
6 | { props.children }
7 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/unstated-next/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "unstated-next": "^1.1.0"
4 | },
5 | "devDependencies": {
6 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/unstated-next/pages/components/CountDisplay.js:
--------------------------------------------------------------------------------
1 | import Count from '../../containers/Count';
2 |
3 | export default function() {
4 | let { count, decrement, increment } = Count.useContainer();
5 | return (
6 |
7 |
8 | {count}
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/unstated-next/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #79F2D2;
4 | }
5 |
--------------------------------------------------------------------------------
/unstated-next/pages/index.js:
--------------------------------------------------------------------------------
1 | import styles from './index.css';
2 | import Count from '../containers/Count';
3 | import CountDisplay from './components/CountDisplay';
4 |
5 | export default function() {
6 | return (
7 |
8 |
Page index
9 |
10 |
11 |
16 |
17 |
18 | );
19 | }
20 |
--------------------------------------------------------------------------------
/unstated-next/pages/users.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #E079F2;
4 | }
5 |
--------------------------------------------------------------------------------
/unstated-next/pages/users.js:
--------------------------------------------------------------------------------
1 |
2 | import styles from './users.css';
3 |
4 | export default function() {
5 | return (
6 |
7 |
Page users
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/zustand/.umirc.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: ['umi-plugin-autolayout'],
3 | };
4 |
5 |
--------------------------------------------------------------------------------
/zustand/README.md:
--------------------------------------------------------------------------------
1 | # zustand
2 |
3 | ## Links
4 |
5 | * https://github.com/react-spring/zustand
6 |
7 |
--------------------------------------------------------------------------------
/zustand/hooks/store.js:
--------------------------------------------------------------------------------
1 | import { create } from 'zustand';
2 |
3 | const [createStore] = create(set => ({
4 | count: 0,
5 | increment: () => set(state => ({ count: state.count + 1 })),
6 | decrement: () => set(state => ({ count: state.count - 1 })),
7 | }));
8 |
9 | export default createStore;
10 |
--------------------------------------------------------------------------------
/zustand/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "zustand": "^2.2.1"
4 | },
5 | "devDependencies": {
6 | "umi-plugin-autolayout": "link:../.plugins/umi-plugin-autolayout"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/zustand/pages/index.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #F279CA;
4 | }
5 |
--------------------------------------------------------------------------------
/zustand/pages/index.js:
--------------------------------------------------------------------------------
1 | import styles from './index.css';
2 | import createStore from "../hooks/store";
3 |
4 | export default function() {
5 | const {
6 | count, increment, decrement,
7 | } = createStore();
8 |
9 | return (
10 |
11 |
Page index
12 | count: { count }
13 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/zustand/pages/users.css:
--------------------------------------------------------------------------------
1 |
2 | .normal {
3 | background: #F2D879;
4 | }
5 |
--------------------------------------------------------------------------------
/zustand/pages/users.js:
--------------------------------------------------------------------------------
1 |
2 | import styles from './users.css';
3 |
4 | export default function() {
5 | return (
6 |
7 |
Page users
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------