skip to Main Content

My crypto calculator should change the opposite field (Amount in, Amount out) based on
API calls. For example, if I choose Ethereum – Bitcoin pair
and I enter 1 in Ethereum field, I will get 0.06902 in Bitcoin field.
If I enter 1 in the Bitcoin field, I get 14,49 in the Ethereum field (real rates).
And my calculator does do that, but I can’t see the change right away. I have to delete the value to see the reflection
in another input box, or I have to change the value to see the reflection in another box (but it will be the previous value).
Same story with Select items, if I select Ethereum and Bitcoin, for example, it doesn’t work. If I change the second token
to DASH, it will show me the price of Ethereum Bitcoin (the previous pair). I’m doing something wrong in my code, I’ll be glad to get any advice
or solution to my problem

Here is the code:

import React, { useState } from 'react';

const Exchange = () => {
    const [SelectOne, setSelectOne] = useState(null);
    const [SelectTwo, setSelectTwo] = useState(null);
    const [DataOne, setDataOne] = useState(null);
    const [DataTwo, setDataTwo] = useState(null);
    const crypto = [
        'btc', 
        'eth', 
        'dash', 
        'dot', 
        'xmr', 
        'bnb', 
        'bch', 
        'etc', 
        'zec', 
        'sol', 
        'ltc', 
        'trx', 
        'zrx', 
        'xrp', 
        'usdt', 
        'usdt', 
        'xtz', 
        'matic',
        'shib',
        'doge'
    ];

    function makeRequest(from, to, amount, which) {
        let accessor = crypto[to].toUpperCase();
        fetch(`https://min-api.cryptocompare.com/data/price?fsym=${crypto[from]}&tsyms=${crypto[to]}`)
        .then(res => res.json())
        .then(data => {
            if (which) {
                setDataTwo(data[accessor] * amount); 
            } else {
                setDataOne(data[accessor] * amount); 
            }       
        });
    }

    function getSelectorTwo(val) {
        setSelectTwo(val.target.value);
        console.log(val.target.value);
        if (SelectOne || SelectTwo != null && SelectOne != SelectTwo) {
            makeRequest(SelectOne, SelectTwo, DataOne, true);
        }
    }

    function getSelectorOne(val) {
        setSelectOne(val.target.value);
        console.log(val.target.value);
        if (SelectOne || SelectTwo != null && SelectOne != SelectTwo) {
            makeRequest(SelectOne, SelectTwo, DataOne, true);
        }
    }

    function getValueOne(val) {
        setDataOne(val.target.value);
        console.log(val.target.value);
        if (SelectOne || SelectTwo != null && SelectOne != SelectTwo) {
            makeRequest(SelectOne, SelectTwo, DataOne, true);
        }
    }

    function getValueTwo(val) {
        setDataTwo(val.target.value);
        console.log(val.target.value);
        if (SelectOne || SelectTwo != null && SelectOne != SelectTwo) {
            makeRequest(SelectTwo, SelectOne, DataTwo, false);
        }
    }

    return (
        <div className="bg-sky-500 h-screen w-screen">
            <div className='container mx-auto '>
                <div className='grid grid-cols-1 gap-4'>
                    <div>
                        <select className='rounded-full text-xl' onChange={getSelectorOne}>
                            <option value={27}>Select currency to send:</option>
                            <option value={0}>Bitcoin</option>
                            <option value={1}>Ethereum</option>
                            <option value={2}>DASH</option>
                            <option value={3}>Polkadot</option>
                            <option value={4}>Monero</option>
                            <option value={5}>Binance Smart Chain</option>
                            <option value={6}>Bitcoin Cash</option>
                            <option value={7}>Ethereum Classic</option>
                            <option value={8}>Zcash</option>
                            <option value={9}>Solana</option>
                            <option value={10}>Litecoin</option>
                            <option value={11}>Tron</option>
                            <option value={12}>0x</option>
                            <option value={13}>Ripple</option>
                            <option value={14}>Tether (ERC20)</option>
                            <option value={15}>Tether (TRC20)</option>
                            <option value={16}>Tezos</option>
                            <option value={17}>Polygon</option>
                            <option value={18}>Shiba Inu</option>
                            <option value={19}>Dogecoin</option>
                        </select>
                    </div>
                    <div>
                        <select className='rounded-full text-xl' onChange={getSelectorTwo}>
                            <option value={27}>Select currency to send:</option>
                            <option value={0}>Bitcoin</option>
                            <option value={1}>Ethereum</option>
                            <option value={2}>DASH</option>
                            <option value={3}>Polkadot</option>
                            <option value={4}>Monero</option>
                            <option value={5}>Binance Smart Chain</option>
                            <option value={6}>Bitcoin Cash</option>
                            <option value={7}>Ethereum Classic</option>
                            <option value={8}>Zcash</option>
                            <option value={9}>Solana</option>
                            <option value={10}>Litecoin</option>
                            <option value={11}>Tron</option>
                            <option value={12}>0x</option>
                            <option value={13}>Ripple</option>
                            <option value={14}>Tether (ERC20)</option>
                            <option value={15}>Tether (TRC20)</option>
                            <option value={16}>Tezos</option>
                            <option value={17}>Polygon</option>
                            <option value={18}>Shiba Inu</option>
                            <option value={19}>Dogecoin</option>
                        </select>
                    </div>
                    <div >
                        <input type={'number'} onChange={getValueOne} value={DataOne} placeholder={'Amout in'} className='p-6 rounded-lg bg-sky-600 outline-none'></input>
                    </div>
                    <div className=''>
                        <input type={'number'} onChange={getValueTwo} value={DataTwo} placeholder={'Amount out'} className='p-6 rounded-lg bg-sky-600 outline-none'></input>
                    </div>
                </div>
            </div>
        </div>
    )
}

I just don’t know where to start researching my problem. I couldn’t find the mistake while reading the React documentation. I’m stuck on it.
And I can’t continue my project without this feature.

2

Answers


  1. You’re gonna slap yourself on the head for this one

    import { useState } from 'react';
    import './App.css';
    
    function App() {
        const [SelectOne, setSelectOne] = useState(null);
        const [SelectTwo, setSelectTwo] = useState(null);
        const [DataOne, setDataOne] = useState(null);
        const [DataTwo, setDataTwo] = useState(null);
        const crypto = [
            'btc', 
            'eth', 
            'dash', 
            'dot', 
            'xmr', 
            'bnb', 
            'bch', 
            'etc', 
            'zec', 
            'sol', 
            'ltc', 
            'trx', 
            'zrx', 
            'xrp', 
            'usdt', 
            'usdt', 
            'xtz', 
            'matic',
            'shib',
            'doge'
        ];
    
        function makeRequest(from, to, amount, which) {
            let accessor = crypto[to].toUpperCase();
            fetch(`https://min-api.cryptocompare.com/data/price?fsym=${crypto[from]}&tsyms=${crypto[to]}`)
            .then(res => res.json())
            .then(data => {
                console.log('DATA', data[accessor] * amount);
                if (which) {
                    setDataTwo(data[accessor] * amount); 
                } else {
                    setDataOne(data[accessor] * amount); 
                }       
            });
        }
    
        function getSelectorTwo(val) {
            setSelectTwo(val.target.value);
            console.log(val.target.value);
            if ((SelectOne !== null || SelectTwo !== null) && SelectOne !== SelectTwo) {
                makeRequest(SelectOne, SelectTwo, DataOne, true);
            }
        }
    
        function getSelectorOne(val) {
            setSelectOne(val.target.value);
            if ((SelectOne !== null || SelectTwo !== null) && SelectOne !== SelectTwo) {
                makeRequest(SelectOne, SelectTwo, DataOne, true);
            }
        }
    
        // Here, you were using DataOne instead of the new value from your input
        function getValueOne(val) {
            setDataOne(val.target.value);
            console.log(val.target.value);
            if ((SelectOne !== null || SelectTwo !== null) && SelectOne !== SelectTwo) {
                makeRequest(SelectOne, SelectTwo, val.target.value, true);
            }
        }
    
        // Here, you were using DataTwo instead of the new value from your input
        function getValueTwo(val) {
            setDataTwo(val.target.value);
            if ((SelectOne !== null || SelectTwo != null) && SelectOne !== SelectTwo) {
                makeRequest(SelectTwo, SelectOne, val.target.value, false);
            }
        }
        
        return (
            <div className="bg-sky-500 h-screen w-screen">
                <div className='container mx-auto '>
                    <div className='grid grid-cols-1 gap-4'>
                        <div>
                            <select className='rounded-full text-xl' onChange={getSelectorOne}>
                                <option value={27}>Select currency to send:</option>
                                <option value={0}>Bitcoin</option>
                                <option value={1}>Ethereum</option>
                                <option value={2}>DASH</option>
                                <option value={3}>Polkadot</option>
                                <option value={4}>Monero</option>
                                <option value={5}>Binance Smart Chain</option>
                                <option value={6}>Bitcoin Cash</option>
                                <option value={7}>Ethereum Classic</option>
                                <option value={8}>Zcash</option>
                                <option value={9}>Solana</option>
                                <option value={10}>Litecoin</option>
                                <option value={11}>Tron</option>
                                <option value={12}>0x</option>
                                <option value={13}>Ripple</option>
                                <option value={14}>Tether (ERC20)</option>
                                <option value={15}>Tether (TRC20)</option>
                                <option value={16}>Tezos</option>
                                <option value={17}>Polygon</option>
                                <option value={18}>Shiba Inu</option>
                                <option value={19}>Dogecoin</option>
                            </select>
                        </div>
                        <div>
                            <select className='rounded-full text-xl' onChange={getSelectorTwo}>
                                <option value={27}>Select currency to send:</option>
                                <option value={0}>Bitcoin</option>
                                <option value={1}>Ethereum</option>
                                <option value={2}>DASH</option>
                                <option value={3}>Polkadot</option>
                                <option value={4}>Monero</option>
                                <option value={5}>Binance Smart Chain</option>
                                <option value={6}>Bitcoin Cash</option>
                                <option value={7}>Ethereum Classic</option>
                                <option value={8}>Zcash</option>
                                <option value={9}>Solana</option>
                                <option value={10}>Litecoin</option>
                                <option value={11}>Tron</option>
                                <option value={12}>0x</option>
                                <option value={13}>Ripple</option>
                                <option value={14}>Tether (ERC20)</option>
                                <option value={15}>Tether (TRC20)</option>
                                <option value={16}>Tezos</option>
                                <option value={17}>Polygon</option>
                                <option value={18}>Shiba Inu</option>
                                <option value={19}>Dogecoin</option>
                            </select>
                        </div>
                        <div >
                            <input type={'number'} onChange={getValueOne} value={DataOne} placeholder={'Amout in'} className='p-6 rounded-lg bg-sky-600 outline-none'></input>
                        </div>
                        <div className=''>
                            <input type={'number'} onChange={getValueTwo} value={DataTwo} placeholder={'Amount out'} className='p-6 rounded-lg bg-sky-600 outline-none'></input>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
    
    export default App;
    

    Your functions were using the old values calling makeRequest(). You were getting val.target.value, which is the new value, but your original value was null, so it would get the value 14.49 and multiply it by 0, giving you a DataTwo of 0!

    Login or Signup to reply.
  2. Setting react state is asynchronous.

    If you create a state like this:

    const [SelectOne, setSelectOne] = useState(null);
    

    And then you call:

    setSelectOne(val.target.value);
    console.log(val.target.value); // new value
    console.log(SelectOne); // old value
    

    Then SelectOne will not have a new value until your component renders again, some milliseconds later.


    What you want here is an effect that calls makeRequest when one of the state values it depends on changes.

    useEffect(() => {
      if (SelectOne || SelectTwo != null && SelectOne != SelectTwo) {
        makeRequest(SelectOne, SelectTwo, DataOne, true);
        // You will have to figure out this last boolean argument, though
      }
    }, [SelectOne, SelectTwo, DataOne, DataTwo])
    

    And now getSelectorOne() (and its friends) is simply something like:

    function getSelectorOne(val) {
      setSelectOne(val.target.value);
    }
    

    Then when that is called:

    1. The component re-renders due to the state change.
    2. The effect notices that SelectOne in the dependency array has changed since the last render
    3. The function is executed, making your request

    In summary, your functions that change state should not also directly trigger hidden side effects.

    Instead, your state changes themselves should trigger side effects via useEffect() with a dependency array that includes the state values that the effect depends on.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search