Witam.
Otóż mam kod renderujący na podstawie typu orderbook giełdy kryptowalut. Ma to działać tak, że w inpucie amount np. gdy chcemy kupić 1000btc ma nam podświetlać ilość transakcji po stronie sprzedających, których łączna wartość daje tyle ile chcemy kupić.
Wpisujemy w inpucie dla komponentu instancji ask, ma podświetlić transakcje dla bid i na odwrót.
Z komponentu nadrzędnego jakim jest OrderbookController.js dane przychodzą prawidłowo czy to przez propsa czy też context, ale mniejsza o to. komponent podrzędny OrderbookTransactions.js porównuje i zwraca do propsa kolejnego komponentu, true lub false i na tej podstawie komponent wie czy ma być podświetlony czy nie.
Brzmi prosto.
Schody pojawiają się gdy do OrderbookTransactions.js dane przychodzą dynamicznie. Nie chcą się podświetlić za cholerę. Przerabiałem różne przypadki z użyciem stanu itd.
Jak wklepie dane na sztywno w w komponencie nadrzędnym do propsa czyli np. tak
<OrderbookTransactions type={type} arrayOfPriceForSelector={[{price: 1.00, type: 'bid', price: 1.12, type: bid}} />
to obydwie instancje OrderbookTransactions dla bid i ask wyrenderują się i wszystko od strzała jest podświetlone tak jak chcę, a jezeli dane pochodzą ze stanu lokalnego komponentu OrderbookController.js i dynamicznie są aktualizowane to nie podświetla się nic.
Z resztą co ja będę mówił, rzućcie okiem na obydwa komponenty i pomyślcie jak to można byłoby rozwiązać wspólnymi siłami.
Komponent nadrzędny OrderbookController.js
import { createContext, useEffect, useState } from 'react'
import Input from 'components/atoms/Input/Input.js'
import { StyledParahraph } from 'components/atoms/StyledParahraph/StyledParahraph.js'
import { StyledPrice } from 'components/atoms/StyledPrice/StyledPrice.js'
import Button from 'components/atoms/Button/Button.js'
import ToggleSwitch from 'components/atoms/ToggleSwitch/ToggleSwitch.js'
import { Wrapper, TypeText, OrderFieldsWrapper, FieldItem, SpanOfField, WrapperControlPanel } from './OrderbookController.styles.js'
import OrderbookTransactions from 'components/organisms/OrderbookTransactions/OrderbookTransactions.js'
import useOrderbookComposition from 'hooks/useOrderbookComposition.js'
import { v4 as uuidv4 } from 'uuid'
import useOrderbookTransactions from 'hooks/useOrderbookTransactions.js'
import { activeTransactionsAction } from 'actions/activeTransactions.js'
import { useDispatch, useSelector } from 'react-redux'
import valuePerEachOrder from 'helpers/ValuePerEachOrder.js'
export const PriceRangeSelectContext = createContext([])
const OrderbookController = ({ type }) => {
const [arrayOfPriceForSelector, setArrayOfPriceForSelector] = useState([])
const dispatch = useDispatch()
const { handleInputChange, inputValues, config } = useOrderbookComposition()
const { currency, symbol, pair } = config
const { createNewOffer, fastTransactions, groupAndSortTransactions } = useOrderbookTransactions(type === "bid" ? "ask" : "bid", pair)
const { user: { _id: userId } } = useSelector(({ user }) => ({ user }))
const { user: { accountBalance }} = useSelector(({ user }) => ({ user }))
const requiredAmount = 1
const handleAddOffer = (type) => {
const { price, amount } = inputValues
const txId = uuidv4()
if((amount * price) > accountBalance) {
console.log(`Masz za mało środków. Stan twojego konta to ${accountBalance}`)
return
}
createNewOffer({ price, amount: amount.replace(',', '.'), pair, type, txId, userId })
dispatch(activeTransactionsAction({ txId, price, amount, pair, type, progress: 28 }))
}
const checkSufficientBalanceForTransaction = () => {
const transactions = valuePerEachOrder(groupAndSortTransactions)
let summaryValueOfRequiredTransactions = 0
for(let value of transactions) {
for(let price in value) {
summaryValueOfRequiredTransactions += requiredAmount * price
if(summaryValueOfRequiredTransactions <= accountBalance && value[price] >= requiredAmount) {
return true
} else {
console.log('Twoje saldo jest mniejsze niż wartość twojego zamówienia, doładuj swoje konto.')
}
}
}
}
const handlePriceRangeSelect = (e) => {
const tempArr = []
let totalAmount = 0
let remainingAmount = requiredAmount
const transactions = valuePerEachOrder(groupAndSortTransactions)
outerLoop:
for (let value of transactions) {
for (let price in value) {
totalAmount += value[price]
tempArr.push({price, type: type === 'bid' ? 'ask' : 'bid'})
if(totalAmount >= requiredAmount) {
break outerLoop;
}
}
}
setArrayOfPriceForSelector(tempArr)
}
const handleFastTransaction = () => {
if(checkSufficientBalanceForTransaction()) {
fastTransactions(type, pair, requiredAmount, null, null, accountBalance)
}
}
return (
<Wrapper>
<TypeText>{type.toUpperCase()}</TypeText>
<OrderFieldsWrapper>
<FieldItem>
<StyledParahraph>Kurs {currency}</StyledParahraph>
<Input type="number" name="price" onChange={handleInputChange} />
</FieldItem>
<SpanOfField>x</SpanOfField>
<FieldItem>
<StyledParahraph>Ilość {symbol}</StyledParahraph>
<Input type="number" name="amount" onChange={(e) => {
handleInputChange(e)
handlePriceRangeSelect(e)
}} />
</FieldItem>
<SpanOfField>=</SpanOfField>
<FieldItem>
<StyledParahraph>Wartość {currency}</StyledParahraph>
<Input type="number" name="value" value={inputValues.totalValue} readOnly />
</FieldItem>
</OrderFieldsWrapper>
<OrderFieldsWrapper>
<WrapperControlPanel>
<ToggleSwitch name="Hidden" />
<ToggleSwitch name="Post only" />
<ToggleSwitch name="Wall" />
</WrapperControlPanel>
<WrapperControlPanel>
<StyledParahraph>Otrzymasz</StyledParahraph>
<StyledPrice>{inputValues.totalAmount || 0}</StyledPrice>
</WrapperControlPanel>
<WrapperControlPanel>
<Button onClick={() => handleFastTransaction()} disabled={!inputValues.isFilled}>{type === 'bid' ? 'FAST BUY' : 'FAST SELL'}</Button>
</WrapperControlPanel>
<WrapperControlPanel>
<Button onClick={() => handleAddOffer(type)} disabled={!inputValues.isFilled}>{type === 'bid' ? 'BUY' : 'SELL'}</Button>
</WrapperControlPanel>
</OrderFieldsWrapper>
<OrderbookTransactions type={type} arrayOfPriceForSelector={arrayOfPriceForSelector} />
</Wrapper>
)
}
export default OrderbookController
import DynamicListWrapper from 'components/atoms/DynamicListWrapper/DynamicListWrapper'
import styled from 'styled-components'
import StyledP from 'components/atoms/ListText/ListText.js'
import useOrderbookTransactions from 'hooks/useOrderbookTransactions.js'
import { useCryptoConfig } from 'hooks/useCryptoConfig.js'
import { useEffect, useContext, useState } from 'react'
import { PriceRangeSelectContext } from 'components/molecules/OrderbookController/OrderbookController.js'
const Wrapper = styled.div`
display: flex;
flex-direction: column;
flex: 1;
padding: 5px 10px;
background-color: rgba(255, 255, 255, .45);
background-image: ${({ theme }) => theme.gradient.white };
border-radius: 10px;
box-shadow: 0px 1px 5px 0px rgba(0, 0, 0, 0.05);
overflow-y: scroll;
`
const OrderbookTransactions = ({ type, arrayOfPriceForSelector }) => {
const [highlightedItems, setHighlightedItems] = useState([])
console.log(arrayOfPriceForSelector)
const handleCheckHighlight = (item) => {
return arrayOfPriceForSelector.some((tx) => {
return item.type === tx.type && item.price == tx.price
})
}
const { pair } = useCryptoConfig().config
const { groupAndSortTransactions } = useOrderbookTransactions(type, pair)
const progress = 50
console.log(groupAndSortTransactions)
return (
<Wrapper>
{groupAndSortTransactions.map((item) => (
<DynamicListWrapper key={item._id} priceRangeSelect={handleCheckHighlight(item)} isOrderbook={true} progress={progress}>
<StyledP>{item.price}</StyledP>
<StyledP>{item.amount.toFixed(8)}</StyledP>
<StyledP>{(item.price * item.amount).toFixed(2)}</StyledP>
<StyledP>54%</StyledP>
</DynamicListWrapper>
))}
</Wrapper>
)
}
export default OrderbookTransactions;
Oczywiście wiem, że kod wymaga zrefaktorowania i poprawek, ale nie o to tutaj teraz chodzi.