recoil store

This commit is contained in:
ShinCurry
2020-07-08 13:49:58 +08:00
parent 49833f30e8
commit fafefe7cd0
9 changed files with 105 additions and 8 deletions

View File

@@ -32,8 +32,12 @@ module.exports = {
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-interface": "off",
"@typescript-eslint/camelcase": "off",
"no-empty": "off",
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "warn",
"react-hooks/exhaustive-deps": ["warn", {
"additionalHooks": "useRecoilCallback"
}],
"react/display-name": "off"
},
"settings": {

View File

@@ -22,6 +22,7 @@
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"recoil": "^0.0.10",
"reflect-metadata": "^0.1.13",
"typescript": "^3.9.6"
},

View File

@@ -1,11 +1,16 @@
import React from 'react';
import './App.css';
import { AppRouter } from './routers/AppRouter';
import { store } from './store';
import { RecoilContainer } from './store/RecoilContainer';
function App() {
return (
<div className="App">
<AppRouter />
<RecoilContainer persistStates={[store.Auth]}>
<AppRouter />
</RecoilContainer>
</div>
);
}

View File

@@ -1,12 +1,24 @@
import React, { useState } from 'react';
import React, { useState, useEffect } from 'react';
import { TextField, Button } from '@hackplan/uui';
import { useInject } from '../hooks/useInject';
import { AuthApi } from '../api/AuthApi';
import { useRecoilState } from 'recoil';
import { store } from '../store';
import useRouter from '../hooks/useRouter';
export function Login() {
const { history } = useRouter()
const [username, setUsername] = useState('uui-template')
const [password, setPassword] = useState('password')
const [auth, setAuth] = useRecoilState(store.Auth)
useEffect(() => {
if (auth && auth.token && auth.user) {
history.push('/')
}
}, [auth, history])
const authApi = useInject(AuthApi)
return (
@@ -24,7 +36,7 @@ export function Login() {
</div>
<Button className="w-full mt-4" onClick={async () => {
const data = await authApi.login({ username, password })
console.log(data)
setAuth(data)
}}>Login</Button>
</div>
</div>

View File

@@ -1,11 +1,13 @@
import React from 'react';
import { Route, RouteProps, Redirect } from 'react-router-dom';
import { Redirect, Route, RouteProps } from 'react-router-dom';
import { useRecoilValue } from 'recoil';
import { store } from '../store';
export const PublicRoute = Route;
export const AuthenticatedRoute = (props: RouteProps) => {
// TODO: implement authenticated check
if (false) {
const isLogin = useRecoilValue(store.isLogin)
if (!isLogin) {
return (
<Redirect
to={{
@@ -15,7 +17,6 @@ export const AuthenticatedRoute = (props: RouteProps) => {
/>
)
}
return (
<Route {...props} />
)

View File

@@ -0,0 +1,41 @@
import React from 'react';
import { RecoilRoot, useRecoilTransactionObserver_UNSTABLE, RecoilState } from 'recoil';
interface RecoilPersistProps {
states: RecoilState<any>[];
}
function RecoilPersist(props: RecoilPersistProps) {
useRecoilTransactionObserver_UNSTABLE(({ snapshot }) => {
for (const state of props.states) {
const { contents } = snapshot.getLoadable(state)
localStorage.setItem(state.key, JSON.stringify(contents))
}
})
return null
}
export interface RecoilContainerProps {
children: React.ReactNode;
persistStates: RecoilPersistProps['states'];
}
export function RecoilContainer(props: RecoilContainerProps) {
return (
<RecoilRoot initializeState={({ set }) => {
for (const persistState of props.persistStates) {
try {
const data = localStorage.getItem(persistState.key)
if (!data) continue
const state = JSON.parse(data)
set(persistState, state)
} catch (error) {
continue
}
}
}}>
<RecoilPersist states={props.persistStates} />
{props.children}
</RecoilRoot>
)
}

18
src/store/index.ts Normal file
View File

@@ -0,0 +1,18 @@
import { atom, selector } from 'recoil';
import { UserAuth } from '../types/User';
const Auth = atom<UserAuth | null>({
key: 'Auth',
default: null,
})
const isLogin = selector<boolean>({
key: 'isLogin',
get: ({ get }) => {
const auth = get(Auth)
return !!auth && !!auth.user && !!auth.token
}
})
export const store = {
Auth, isLogin,
}

10
src/types/User.ts Normal file
View File

@@ -0,0 +1,10 @@
export interface User {
name: string;
avatar: string;
email: string;
}
export interface UserAuth {
token: string;
user: User;
}

View File

@@ -9356,6 +9356,11 @@ realpath-native@^1.1.0:
dependencies:
util.promisify "^1.0.0"
recoil@^0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/recoil/-/recoil-0.0.10.tgz#679ab22306f559f8a63c46fd5ff5241539f9248f"
integrity sha512-+9gRqehw3yKETmoZbhSnWu4GO10HDb5xYf1CjLF1oXGK2uT6GX5Lu9mfTXwjxV/jXxEKx8MIRUUbgPxvbJ8SEw==
recursive-readdir@2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.2.tgz#9946fb3274e1628de6e36b2f6714953b4845094f"