prevent extra rerenders

This commit is contained in:
Tyler Shipe 2021-04-15 02:16:36 -04:00
parent 0c3ea08764
commit faa466ca17
15 changed files with 106 additions and 143 deletions

View File

@ -61,9 +61,7 @@ const FeeDiscountsTable = () => {
</Button>
</div>
</div>
) : (
<Button disabled>Connect Wallet</Button>
)}
) : null}
</div>
{showDeposit && (
<DepositSrmModal isOpen={showDeposit} onClose={handleCloseDeposit} />

View File

@ -1,13 +1,20 @@
import React from 'react'
import React, { FunctionComponent } from 'react'
export default function FloatingElement({ shrink = false, children }) {
type FloatingElementProps = {
className?: string
}
const FloatingElement: FunctionComponent<FloatingElementProps> = ({
className,
children,
}) => {
return (
<div
className={`m-1 p-4 bg-th-bkg-2 rounded-lg overflow-auto ${
shrink ? null : `h-full`
}`}
className={`p-2 h-full bg-th-bkg-2 rounded-lg overflow-hidden ${className}`}
>
{children}
<div className="h-full overflow-auto thin-scroll p-2">{children}</div>
</div>
)
}
export default FloatingElement

View File

@ -13,7 +13,7 @@ import DepositModal from './DepositModal'
import WithdrawModal from './WithdrawModal'
import Button from './Button'
export default function MarginStats() {
export default function MarginBalances() {
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
const selectedMarginAccount = useMangoStore(
(s) => s.selectedMarginAccount.current

View File

@ -3,9 +3,8 @@ import { useEffect, useState } from 'react'
import { nativeToUi } from '@blockworks-foundation/mango-client/lib/utils'
import { groupBy } from '../utils'
import useTradeHistory from '../hooks/useTradeHistory'
import useConnection from '../hooks/useConnection'
import useMangoStore from '../stores/useMangoStore'
import FloatingElement from './FloatingElement'
import useMarginAccount from '../hooks/useMarginAccount'
const calculatePNL = (tradeHistory, prices, mangoGroup) => {
if (!tradeHistory.length) return '0.00'
@ -52,9 +51,12 @@ const calculatePNL = (tradeHistory, prices, mangoGroup) => {
return total.toFixed(2)
}
export default function MarginStats() {
const { connection } = useConnection()
const { marginAccount, mangoGroup } = useMarginAccount()
export default function MarginInfo() {
const connection = useMangoStore((s) => s.connection.current)
const selectedMarginAccount = useMangoStore(
(s) => s.selectedMarginAccount.current
)
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
const [mAccountInfo, setMAccountInfo] = useState<
| {
label: string
@ -65,24 +67,28 @@ export default function MarginStats() {
}[]
| null
>(null)
const { tradeHistory } = useTradeHistory()
const tradeHistory = useTradeHistory()
useEffect(() => {
if (mangoGroup) {
mangoGroup.getPrices(connection).then((prices) => {
const collateralRatio = marginAccount
? marginAccount.getCollateralRatio(mangoGroup, prices)
if (selectedMangoGroup) {
selectedMangoGroup.getPrices(connection).then((prices) => {
const collateralRatio = selectedMarginAccount
? selectedMarginAccount.getCollateralRatio(selectedMangoGroup, prices)
: 200
const accountEquity = marginAccount
? marginAccount.computeValue(mangoGroup, prices)
const accountEquity = selectedMarginAccount
? selectedMarginAccount.computeValue(selectedMangoGroup, prices)
: 0
let leverage
if (marginAccount) {
if (selectedMarginAccount) {
leverage = accountEquity
? (
1 /
(marginAccount.getCollateralRatio(mangoGroup, prices) - 1)
(selectedMarginAccount.getCollateralRatio(
selectedMangoGroup,
prices
) -
1)
).toFixed(2)
: '∞'
} else {
@ -106,7 +112,7 @@ export default function MarginStats() {
},
{
label: 'Total PNL',
value: calculatePNL(tradeHistory, prices, mangoGroup),
value: calculatePNL(tradeHistory, prices, selectedMangoGroup),
unit: '',
currency: '$',
desc:
@ -123,7 +129,7 @@ export default function MarginStats() {
},
{
label: 'Maint. Collateral Ratio',
value: (mangoGroup.maintCollRatio * 100).toFixed(0),
value: (selectedMangoGroup.maintCollRatio * 100).toFixed(0),
unit: '%',
currency: '',
desc:
@ -131,7 +137,7 @@ export default function MarginStats() {
},
{
label: 'Initial Collateral Ratio',
value: (mangoGroup.initCollRatio * 100).toFixed(0),
value: (selectedMangoGroup.initCollRatio * 100).toFixed(0),
currency: '',
unit: '%',
desc: 'The collateral ratio required to open a new margin position',
@ -140,7 +146,7 @@ export default function MarginStats() {
})
}
// eslint-disable-next-line
}, [marginAccount, mangoGroup])
}, [selectedMarginAccount, selectedMangoGroup])
return (
<FloatingElement>
<>

View File

@ -13,7 +13,6 @@ import MenuItem from './MenuItem'
import ThemeSwitch from './ThemeSwitch'
import WalletIcon from './WalletIcon'
import UiLock from './UiLock'
import DropMenu from './DropMenu'
import { useRouter } from 'next/router'
import WalletSelect from './WalletSelect'
import useMangoStore from '../stores/useMangoStore'

View File

@ -1,7 +1,7 @@
import useTradeHistory from '../hooks/useTradeHistory'
const TradeHistoryTable = () => {
const { tradeHistory } = useTradeHistory()
const tradeHistory = useTradeHistory()
return (
<div className={`flex flex-col py-6`}>
@ -61,7 +61,7 @@ const TradeHistoryTable = () => {
<tbody>
{tradeHistory.map((trade, index) => (
<tr
key={`${trade.orderId}${trade.side}`}
key={`${trade.orderId}${trade.side}${trade.uuid}`}
className={`
${index % 2 === 0 ? `bg-th-bkg-3` : `bg-th-bkg-2`}
`}

View File

@ -7,7 +7,7 @@ const TVChartContainer = dynamic(
)
import FloatingElement from '../components/FloatingElement'
import Orderbook from '../components/Orderbook'
import MarginStats from './MarginStats'
import MarginInfo from './MarginInfo'
import MarginBalances from './MarginBalances'
import TradeForm from './TradeForm'
import UserInfo from './UserInfo'
@ -21,7 +21,7 @@ const layouts = {
{ i: 'tvChart', x: 0, y: 0, w: 3, h: 30 },
{ i: 'orderbook', x: 3, y: 0, w: 1, h: 17 },
{ i: 'tradeForm', x: 4, y: 0, w: 1, h: 17 },
{ i: 'marginStats', x: 4, y: 2, w: 1, h: 12 },
{ i: 'marginInfo', x: 4, y: 2, w: 1, h: 12 },
{ i: 'marketTrades', x: 3, y: 1, w: 1, h: 13 },
{ i: 'userInfo', x: 0, y: 2, w: 4, h: 17 },
{ i: 'balanceInfo', x: 4, y: 1, w: 1, h: 13 },
@ -29,7 +29,7 @@ const layouts = {
lg: [
{ i: 'tvChart', x: 0, y: 0, w: 2, h: 24 },
{ i: 'balanceInfo', x: 2, y: 0, w: 1, h: 13 },
{ i: 'marginStats', x: 2, y: 1, w: 1, h: 11 },
{ i: 'marginInfo', x: 2, y: 1, w: 1, h: 11 },
{ i: 'orderbook', x: 0, y: 2, w: 1, h: 17 },
{ i: 'tradeForm', x: 1, y: 2, w: 1, h: 17 },
{ i: 'marketTrades', x: 2, y: 2, w: 1, h: 17 },
@ -63,8 +63,8 @@ const TradePageGrid = () => {
<div key="tradeForm">
<TradeForm />
</div>
<div key="marginStats">
<MarginStats />
<div key="marginInfo">
<MarginInfo />
</div>
<div key="userInfo">
<UserInfo />

View File

@ -15,12 +15,12 @@ const UiLock = ({ className = '' }) => {
<div className={`flex relative ${className}`}>
<button
onClick={handleClick}
className="w-10 h-10 flex items-center justify-center hover:text-th-primary rounded-mdbg-transparent rounded hover:text-th-primary focus:outline-none"
className="w-10 h-10 flex items-center justify-center bg-transparent rounded hover:text-th-primary focus:outline-none"
>
{uiLocked ? (
<LockClosedIcon className="w-5 h-5" />
) : (
<LockOpenIcon className="w-5 h-5" />
<LockOpenIcon className="w-5 h-5 animate-bounce" />
)}
</button>
</div>

View File

@ -4,9 +4,7 @@ import { IDS } from '@blockworks-foundation/mango-client'
import useMangoStore from '../stores/useMangoStore'
const useConnection = () => {
// console.log('loading useConnection')
const setSolanaStore = useMangoStore((s) => s.set)
const setMangoStore = useMangoStore((s) => s.set)
const { cluster, current: connection, endpoint } = useMangoStore(
(s) => s.connection
)
@ -16,17 +14,17 @@ const useConnection = () => {
])
useEffect(() => {
// @ts-ignore
if (connection && endpoint === connection._rpcEndpoint) return
if (connection && endpoint === connection['_rpcEndpoint']) return
console.log('setting new connection')
const newConnection = new Connection(endpoint, 'recent')
setSolanaStore((state) => {
setMangoStore((state) => {
state.connection.current = newConnection
})
}, [endpoint])
useEffect(() => {
if (connection && endpoint === connection['_rpcEndpoint']) return
const id = connection.onAccountChange(new Account().publicKey, () => {})
return () => {
connection.removeAccountChangeListener(id)
@ -34,6 +32,7 @@ const useConnection = () => {
}, [endpoint])
useEffect(() => {
if (connection && endpoint === connection['_rpcEndpoint']) return
const id = connection.onSlotChange(() => null)
return () => {
connection.removeSlotChangeListener(id)

View File

@ -18,9 +18,14 @@ const useHydrateStore = () => {
const setSerumStore = useSerumStore((s) => s.set)
const selectedMarketAddress = useMangoStore(marketAddressSelector)
const marketsForSelectedMangoGroup = useMangoStore(mangoGroupMarketsSelector)
const actions = useMangoStore((s) => s.actions)
const { connection, dexProgramId } = useConnection()
const { marketList } = useMarketList()
useEffect(() => {
actions.fetchMangoGroup()
}, [actions])
// load selected market
useEffect(() => {
Market.load(
@ -76,7 +81,7 @@ const useHydrateStore = () => {
})
}, [marketList])
// hydrate orderbook for all markets in mango group
// hydrate orderbook with all markets in mango group
useEffect(() => {
const subscriptionIds = Object.entries(marketsForSelectedMangoGroup).map(
([, market]) => {
@ -131,6 +136,7 @@ const useHydrateStore = () => {
}
}, [marketsForSelectedMangoGroup])
// fetch filled trades for selected market
useInterval(() => {
async function fetchFills() {
const market = useMangoStore.getState().market.current

View File

@ -23,12 +23,6 @@ const useMarginAccount = () => {
}
}, [connected, actions])
useEffect(() => {
if (selectedMarginAccount) {
actions.fetchTradeHistory()
}
}, [selectedMarginAccount])
useInterval(() => {
if (connected) {
actions.fetchMarginAccounts()

View File

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react'
import { useEffect, useRef } from 'react'
import useMangoStore from '../stores/useMangoStore'
import useSerumStore from '../stores/useSerumStore'
import useMarket from './useMarket'
@ -19,7 +19,7 @@ const formatTradeHistory = (newTradeHistory) => {
marketName: trade.marketName
? trade.marketName
: `${trade.baseCurrency}/${trade.quoteCurrency}`,
key: `${trade.orderId}${trade.side}${trade.uuid}`,
key: `${trade.orderId}-${trade.uuid}`,
liquidity: trade.maker || trade?.eventFlags?.maker ? 'Maker' : 'Taker',
}
})
@ -27,7 +27,17 @@ const formatTradeHistory = (newTradeHistory) => {
}
const useFills = () => {
const fills = useSerumStore((s) => s.fills)
const fillsRef = useRef(useSerumStore.getState().fills)
const fills = fillsRef.current
useEffect(
() =>
useSerumStore.subscribe(
(fills) => (fillsRef.current = fills as []),
(state) => state.fills
),
[]
)
const { market, marketName } = useMarket()
const marginAccount = useMangoStore((s) => s.selectedMarginAccount.current)
const selectedMangoGroup = useMangoStore((s) => s.selectedMangoGroup.current)
@ -44,7 +54,6 @@ const useFills = () => {
export const useTradeHistory = () => {
const eventQueueFills = useFills()
const [allTrades, setAllTrades] = useState<any[]>([])
const tradeHistory = useMangoStore((s) => s.tradeHistory)
const marginAccount = useMangoStore((s) => s.selectedMarginAccount.current)
const actions = useMangoStore((s) => s.actions)
@ -55,22 +64,19 @@ export const useTradeHistory = () => {
}
}, 12000)
useEffect(() => {
if (eventQueueFills && eventQueueFills.length > 0) {
const newFills = eventQueueFills.filter(
(fill) =>
!tradeHistory.find((t) => t.orderId === fill.orderId.toString())
)
const newTradeHistory = [...newFills, ...tradeHistory]
if (newFills.length > 0 && newTradeHistory.length !== allTrades.length) {
const formattedTradeHistory = formatTradeHistory(newTradeHistory)
setAllTrades(formattedTradeHistory)
}
const allTrades = []
if (eventQueueFills && eventQueueFills.length > 0) {
const newFills = eventQueueFills.filter(
(fill) =>
!tradeHistory.flat().find((t) => t.orderId === fill.orderId.toString())
)
const newTradeHistory = [...newFills, ...tradeHistory]
if (newFills.length > 0 && newTradeHistory.length !== allTrades.length) {
return formatTradeHistory(newTradeHistory)
}
}, [tradeHistory, eventQueueFills])
}
return { tradeHistory: allTrades }
return tradeHistory.flat()
}
export default useTradeHistory

View File

@ -191,7 +191,7 @@ export default function StatsPage() {
<div className={`bg-th-bkg-1 text-th-fgd-1 transition-all `}>
<TopBar />
<div className="min-h-screen w-full lg:w-2/3 mx-auto p-1 sm:px-2 sm:py-1 md:px-6 md:py-1">
<FloatingElement>
<FloatingElement className="h-auto">
<div className="text-center">
<h1 className={`text-th-fgd-1 text-3xl`}>Mango Stats</h1>
</div>
@ -253,7 +253,7 @@ export default function StatsPage() {
</div>
</FloatingElement>
{selectedAsset ? (
<FloatingElement shrink>
<FloatingElement className="h-auto">
<div className="flex justify-center text-2xl">
<span className={`text-th-fgd-1`}>Historical</span>
<Select

View File

@ -67,78 +67,37 @@ button {
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
/* display: none; <- Crashes Chrome on hover */
-webkit-appearance: none;
margin: 0; /* <-- Apparently some margin are still there even though it's hidden */
margin: 0;
}
input[type='number'] {
-moz-appearance: textfield; /* Firefox */
-moz-appearance: textfield;
}
/* TODO: remove. styling for old ant components below */
.ant-input-group-addon {
background-color: transparent !important;
.thin-scroll {
overflow: hidden !important;
}
.ant-switch {
background-color: #5b5868 !important;
.thin-scroll:hover {
overflow: auto !important;
}
.ant-switch-checked {
background-color: #f2c94c !important;
.thin-scroll::-webkit-scrollbar {
width: 4px;
height: 8px;
background-color: var(--bkg-2);
}
.ant-switch-handle::before {
background-color: #ffffff !important;
.thin-scroll::-webkit-scrollbar-thumb {
border-radius: 4px;
background-color: var(--bkg-3);
}
.ant-input-affix-wrapper-disabled {
background-color: #262337 !important;
color: #ffffff !important;
.thin-scroll::-webkit-scrollbar-track {
background-color: inherit;
}
.ant-select-arrow {
color: #817f8a !important;
}
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
color: #f2c94c !important;
font-weight: 600 !important;
background-color: #141026 !important;
}
.ant-select-item-option-active:not(.ant-select-item-option-disabled) {
background-color: #584f81 !important;
}
.ant-input-group::after {
border-style: none !important;
}
.ant-input-group::before {
border-style: none !important;
}
.ant-input-group-wrapper {
border-style: none !important;
}
.ant-input-group:first-child .ant-input-affix-wrapper:not(:first-child) {
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
}
.ant-input-group.ant-input-group-compact > *:last-child,
.ant-input-group.ant-input-group-compact
> .ant-select:last-child
> .ant-select-selector,
.ant-input-group.ant-input-group-compact
> .ant-cascader-picker:last-child
.ant-input,
.ant-input-group.ant-input-group-compact
> .ant-cascader-picker-focused:last-child
.ant-input {
border-color: #524a79 !important;
.thin-scroll::-webkit-scrollbar-corner {
background-color: var(--bkg-3);
}

View File

@ -16,6 +16,9 @@ module.exports = {
fontFamily: {
sans: ['Nunito'],
},
fontSize: {
xxs: '.6rem',
},
colors: {
'mango-orange': {
DEFAULT: '#DFAB01',
@ -94,20 +97,6 @@ module.exports = {
'th-green': 'var(--green)',
},
},
fontSize: {
xxs: '.6rem',
// 'sm': '.875rem',
// 'tiny': '.875rem',
// 'base': '1rem',
// 'lg': '1.125rem',
// 'xl': '1.25rem',
// '2xl': '1.5rem',
// '3xl': '1.875rem',
// '4xl': '2.25rem',
// '5xl': '3rem',
// '6xl': '4rem',
// '7xl': '5rem',
},
},
variants: {
extend: {