# 5-3. Count Component

`src/components/Count.js`에 대한 설명입니다.

## `Count` 컴포넌트 <a href="#count-component" id="count-component"></a>

1\) Full code\
2\) `Count` component's role\
3\) How to interact with contract?\ 4) Interact with contract: `getCount` method\
5\) Interact with contract: `setPlus` method\
6\) Transaction life cycle

### 1) Full code <a href="#id-1-full-code" id="id-1-full-code"></a>

```javascript
import React, { Component } from 'react'
import cx from 'classnames'

import { cav } from 'klaytn/caver'

import './Count.scss'

class Count extends Component {
  constructor() {
    super()
    // ** 1. 컨트랙트 인스턴스 생성 **
    // 예시: new cav.klay.Contract(DEPLOYED_ABI, DEPLOYED_ADDRESS)
    // 이 인스턴스를 통해 컨트랙트 메서드를 호출할 수 있습니다.
    // 이제 `this.countContract` 변수로 이 인스턴스에 접근할 수 있습니다.
    this.countContract = DEPLOYED_ABI
      && DEPLOYED_ADDRESS
      && new cav.klay.Contract(DEPLOYED_ABI, DEPLOYED_ADDRESS)
    this.state = {
      count: '',
      lastParticipant: '',
      isSetting: false,
    }
  }

  intervalId = null

  getCount = async () => {
    // ** 2. 컨트랙트 메서드 호출(CALL) **
    // 예시: this.countContract.methods.methodName(arguments).call()
    // 위와 같이 컨트랙트 메서드(CALL)를 호출할 수 있습니다.
    // 예를 들어 컨트랙트에 `count`라는 메서드가 있을 때,
    // 해당 메서드를 아래와 같이 호출할 수 있습니다.
    // 예시: this.countContract.methods.count().call()
    // 이는 프로미스를 반환하므로 .then() 또는 async-await으로 접근할 수 있습니다.
    const count = await this.countContract.methods.count().call()
    const lastParticipant = await this.countContract.methods.lastParticipant().call()
    this.setState({
      count,
      lastParticipant,
    })
  }

  setPlus = () => {
    const walletInstance = cav.klay.accounts.wallet && cav.klay.accounts.wallet[0]

    // 컨트랙트 메서드 호출을 위해 지갑을 연동해야 합니다.
    if (!walletInstance) return

    this.setState({ settingDirection: 'plus' })

    // 3. ** 컨트랙트 메서드 호출 (SEND) **
    // 예시: this.countContract.methods.methodName(arguments).send(txObject)
    // 위와 같이 컨트랙트 메서드(SEND)를 호출할 수 있습니다.
    // 예를 들어 컨트랙트에 `plus`라는 메서드가 있을 때,
    // You can call it like below:
    // ex:) this.countContract.methods.plus().send({
    //   from: '0x952A8dD075fdc0876d48fC26a389b53331C34585', // PUT YOUR ADDRESS
    //   gas: '200000',
    // })
    try{
      this.countContract.send({
        from: walletInstance.address,
        gas: '200000',
      }, 'plus')
        .then((receipt) => {
          console.log(`
            Received receipt! It means your transaction(calling plus function)
            is in klaytn block(#${receipt.blockNumber})
          `, receipt)
          this.setState({
            settingDirection: null,
            txHash: receipt.transactionHash,
          })
        })
    } catch (error) {
      alert(err.message)
      this.setState({ settingDirection: null })
    }
  }

  setMinus = () => {
    const walletInstance = cav.klay.accounts.wallet && cav.klay.accounts.wallet[0]

    // Need to integrate wallet for calling contract method.
    if (!walletInstance) return

    this.setState({ settingDirection: 'minus' })

    // 3. ** Call contract method (SEND) **
    // ex:) this.countContract.methods.methodName(arguments).send(txObject)
    // You can call contract method (SEND) like above.
    // 예를 들어 컨트랙트에 `minus`라는 메서드가 있을 때,
    // 해당 메서드를 다음과 같이 호출할 수 있습니다.
    // 예시: this.countContract.methods.minus().send({
    //   from: '0x952A8dD075fdc0876d48fC26a389b53331C34585', // 본인의 주소를 적으세요.
    //   gas: '200000',
    // })

    // 이는 이벤트 이미터를 반환하므로 전송 후에 이벤트로 결과를 받아올 수 있습니다.
    // .on('transactionHash') 이벤트를 사용하세요.
    // : 트랜잭션을 전송한 후 로직을 처리하려는 경우
    // .once('receipt') 이벤트를 사용하세요.
    // : 트랜잭션이 블록에 포함된 후 로직을 처리하려는 경우
    // ex:) .once('receipt', (data) => {
    //   console.log(data)
    // })
    try{
      this.countContract.send({
        from: walletInstance.address,
        gas: '200000',
      }, 'minus')
        .then((receipt) => {
          console.log(`
            Received receipt! It means your transaction(calling minus function)
            is in klaytn block(#${receipt.blockNumber})
          `, receipt)
          this.setState({
            settingDirection: null,
            txHash: receipt.transactionHash,
          })
        })
    } catch (error) {
      alert(err.message)
      this.setState({ settingDirection: null })
    }
  }

  componentDidMount() {
    this.intervalId = setInterval(this.getCount, 1000)
  }

  componentWillUnmount() {
    clearInterval(this.intervalId)
  }

  render() {
    const { lastParticipant, count, settingDirection, txHash } = this.state
    return (
      <div className="Count">
        {lastParticipant && (
          <div className="Count__lastParticipant">
            last participant: {lastParticipant}
          </div>
        )}
        <div className="Count__count">COUNT: {count}</div>
        <button
          onClick={this.setPlus}
          className={cx('Count__button', {
            'Count__button--setting': settingDirection === 'plus',
          })}
        >
          +
        </button>
        <button
          onClick={this.setMinus}
          className={cx('Count__button', {
            'Count__button--setting': settingDirection === 'minus',
          })}
        >
          -
        </button>
        {txHash && (
          <div className="Count__lastTransaction">
            <p className="Count__lastTransactionMessage">
              You can check your last transaction in klaytn scope:
            </p>
            <a
              target="_blank"
              href={`https://baobab.klaytnfinder.io/tx/${txHash}`}
              className="Count__lastTransactionLink"
            >
              {txHash}
            </a>
          </div>
        )}
      </div>
    )
  }
}

export default Count
```

### 2) `Count` component's role <a href="#id-2-count-component-s-role" id="id-2-count-component-s-role"></a>

`'Count'` 컴포넌트의 역할은 Klaytn 블록체인에 배포된 Count 컨트랙트와 상호작용하는 것입니다.

In Count.sol, we declared several variables and functions like below:\
1.`count`\
2.`lastParticipant`\
3.`plus` - increase `count` storage variable by 1. (count = count + 1)\
4.`minus` - decrease `count` storage variable by 1. (count = count - 1)

Count.js 컴포넌트에는 Count 컨트랙트의 함수 및 변수와 상호작용하는 메서드가 있습니다.

### 3) How to interact with contract? <a href="#id-3-how-to-interact-with-contract" id="id-3-how-to-interact-with-contract"></a>

To interact with the contract, we need a contract instance of the deployed contract.\
The contract instance can be made through `caver.klay.Contract(ABI, contractAddress)` API of caver-js. 자세한 내용은 [caver.klay.Contract](/content/dapp/sdk/caver-js/v1.4.1/api-references/caver.klay.contract.md#new-contract)을 참고해주세요.

With `Contract ABI`(Application Binary Interface), caver can call the contract method as if it is a local function,\
for example)\ `contractInstance.methods.count().call()`\
`contractInstance.methods.plus().send({ ... })`\
`contractInstance.methods.minus().send({ ... })`

`Contract address`는 해당 컨트랙트의 컴파일 및 배포 이후에 `build/contracts/Count.json` 파일에서 찾을 수 있습니다. 여러분의 편의를 위해 Klaytn 테스트넷에 해당 컨트랙트를 배포하고 `deployedABI`와 `deployedAddress` 파일을 디렉토리에 넣어두었습니다. Those files contain the ABI of the Count contract and the deployed contract address.\
Thanks to the webpack configuration, we can access them via variables. (`DEPLOYED_ADDRESS`, `DEPLOYED_ABI`)

For example)\
`DEPLOYED_ADDRESS` returns the deployed contact ddress.\
`DEPLOYED_ABI` returns the Count contract ABI.

```javascript
constructor() {
  super()
  // ** 1. 컨트랙트 인스턴스 생성 **
    // 예시: new cav.klay.Contract(DEPLOYED_ABI, DEPLOYED_ADDRESS)
    // 이 인스턴스를 통해 컨트랙트 메서드를 호출할 수 있습니다.
  // Now you can access the instance by `this.countContract` variable.
  this.countContract = DEPLOYED_ABI
    && DEPLOYED_ADDRESS
    && new cav.klay.Contract(DEPLOYED_ABI, DEPLOYED_ADDRESS)
  ...
}
```

`this.countContract = new cav.klay.Contract(DEPLOYED_ABI, DEPLOYED_ADDRESS)`는 `DEPLOYED_ABI`와 `DEPLOYED_ADDRESS`를 `cav.klay.Contract` API에 전달하여 배포된 `Count` 컨트랙트와 상호작용할 컨트랙트 인스턴스를 생성합니다. 그리고 이 컨트랙트 인스턴스는 `this.countContract`에 저장됩니다.

### 4) Interact with contract: `getCount` method <a href="#id-4-interact-with-contract-getcount-method" id="id-4-interact-with-contract-getcount-method"></a>

```javascript
getCount = async () => {
  // ** 2. 컨트랙트 메서드 호출(CALL) **
    // 예시: this.countContract.methods.methodName(arguments).call()
    // 위와 같이 컨트랙트 메서드(CALL)를 호출할 수 있습니다.
  // For example, your contract has a method called `count`.
  // 해당 메서드를 아래와 같이 호출할 수 있습니다.
    // 예시: this.countContract.methods.count().call()
    // 이는 프로미스를 반환하므로 .then() 또는 async-await으로 접근할 수 있습니다.
  const count = await this.countContract.methods.count().call()
  const lastParticipant = await this.countContract.methods.lastParticipant().call()
  this.setState({
    count,
    lastParticipant,
  })
}
```

컨트랙트 인스턴스가 있으므로 컨트랙트 메서드를 호출할 수 있습니다. Contract instance has a property, `methods`.\
It contains the functions of the contract, for example, `count`, `lastParticipant`, `plus`, and `minus`.

컨트랙트 함수 호출이 프로미스 객체를 반환하기 때문에 위 코드에서 `getCount` 함수는 `async`로 선언되었습니다. We can fetch the `count` by calling `this.countContract.methods.count().call()`.\
We can fetch the `lastParticipant` address by calling `this.countContract.methods.lastParticipant().call()`.\
After fetching those variables, we set the state properties, `count` and `lastParticipant` with the received values.

컨트랙트 메서드 호출에 대한 자세한 안내는 [caver.klay.Contract](/content/dapp/sdk/caver-js/v1.4.1/api-references/caver.klay.contract.md#methods)를 참고해주세요.

```javascript
componentDidMount() {
  this.intervalId = setInterval(this.getCount, 1000)
}

componentWillUnmount() {
  clearInterval(this.intervalId)
}
```

We want to fetch the `count` variable per 1 second, it can be achieved by `setInterval`.\
It is the same as we did in the `getBlockNumber` in `BlockNumber.js` which calls `caver.klay.getBlockNumber()` intervally.

### 5) Interact with contract: `setPlus` method <a href="#id-5-interact-with-contract-setplus-method" id="id-5-interact-with-contract-setplus-method"></a>

```javascript
setPlus = () => {
  const walletInstance = cav.klay.accounts.wallet && cav.klay.accounts.wallet[0]

  // 컨트랙트 메서드 호출을 위해 지갑을 연동해야 합니다.
  if (!walletInstance) return

  this.setState({ settingDirection: 'plus' })

  // 3. ** 컨트랙트 메서드 호출(SEND) **
    // 예시: this.countContract.methods.methodName(arguments).send(txObject)
    // 위와 같이 컨트랙트 메서드(SEND)를 호출할 수 있습니다.
  // For example, your contract has a method called `plus`.
  // You can call it like below:
  // ex:) this.countContract.methods.plus().send({
  //   from: '0x952A8dD075fdc0876d48fC26a389b53331C34585', // PUT YOUR ADDRESS
  //   gas: '200000',
  // })
  try{
    this.countContract.send({
      from: walletInstance.address,
      gas: '200000',
    }, 'plus')
      .then((receipt) => {
        console.log(`
          Received receipt! It means your transaction(calling plus function)
          is in klaytn block(#${receipt.blockNumber})
        `, receipt)
        this.setState({
          settingDirection: null,
          txHash: receipt.transactionHash,
        })
      })
  } catch (error) {
    alert(err.message)
    this.setState({ settingDirection: null })
  }
}
```

`setPlus` 함수는 Count 컴포넌트에서 가장 중요한 부분입니다. 이 함수는 컨트랙트 함수인 `plus`를 호출하여 컨트랙트와 상호작용합니다. Since this function is also a contract method, it is contained in the `this.counterContract.methods`.\
However, unlike `count` and `lastParticipant` that just reads data, `plus` function **writes data** to the Klaytn blockchain.\
Reading data is free, however writing data incurs cost for the use of computation and storage. 그리고 그 비용은 사용한 `gas`의 양에 따라 측정됩니다.

따라서 트랜잭션을 보내려면 트랜잭션 수수료를 담당하는 Klaytn 노드에게 `from:` 속성을 알려야 합니다. `gas:` 트랜잭션 발신자가 트랜잭션을 보낼 때 지불하고자 하는 최대 가스양을 나타내는 속성입니다.

```javascript
this.countContract.methods.plus().send({
  from: walletInstance.address,
  gas: '200000',
})
```

트랜잭션을 보내려면 `.call()` 대신 `.send()`을 사용하는 것이 좋습니다.

```javascript
.send({
  from: ...,
  gas: ...
})
```

### 6) Transaction life cycle <a href="#id-6-transaction-life-cycle" id="id-6-transaction-life-cycle"></a>

```javascript
try{
  this.countContract.send({
    from: walletInstance.address,
    gas: '200000',
  }, 'plus')
    .then((receipt) => {
      console.log(`
        Received receipt! It means your transaction(calling plus function)
        is in klaytn block(#${receipt.blockNumber})
      `, receipt)
      this.setState({
        settingDirection: null,
        txHash: receipt.transactionHash,
      })
    })
} catch (error) {
  alert(err.message)
  this.setState({ settingDirection: null })
}
```

After sending a transaction, you can get the transaction status along the life cycle.\
`transactionHash` event is fired when you get the transaction hash. It is available before sending the transaction over the network.\
`receipt` is fired,when you can get the transaction receipt. 이는 트랜잭션이 블록에 들어갔음을 의미합니다. You can get the block number that contains your transaction by `receipt.blockNumber`.\
`error` is fired when an error occurred while sending a transaction.

cf) `settingDirection` is used to display a loading indicator(gif). 트랜잭션이 블록에 포함되면 `settingDirection`을 `null`로 설정하여 로딩 표시기를 제거하세요.

```javascript
<button
  onClick={this.setPlus}
  className={cx('Count__button', {
    'Count__button--setting': settingDirection === 'plus',
  })}
>
  +
</button>
```

* 버튼을 클릭하여 이 기능을 호출할 수 있게 됩니다.
* 버튼을 누른 후의 과정을 요약하면 다음과 같습니다.

1. 컨트랙트 메서드인 `plus`를 호출하여 트랜잭션을 보냅니다.
2. Just after sending a transaction, you will receive the transaction hash.\
   3-a. After your transaction has been processed and included in a block, you will receive the transaction receipt.\ 3-b. 트랜잭션을 보내는 동안 에러가 발생하면 에러 메세지를 받습니다. 그리고 `receipt` 블록은 호출되지 않습니다.

`plus` 메서드를 호출하는 전체 코드는 다음과 같습니다.

```javascript
try{
  this.countContract.send({
    from: walletInstance.address,
    gas: '200000',
  }, 'plus')
    .then((receipt) => {
      console.log(`
        Received receipt! It means your transaction(calling plus function)
        is in klaytn block(#${receipt.blockNumber})
      `, receipt)
      this.setState({
        settingDirection: null,
        txHash: receipt.transactionHash,
      })
    })
} catch (error) {
  alert(err.message)
  this.setState({ settingDirection: null })
}
```

### 블록체인에서 어떻게 트랜잭션을 확인할 수 있나요? <a href="#how-can-i-check-my-transaction-in-the-blockchain" id="how-can-i-check-my-transaction-in-the-blockchain"></a>

![트랜잭션 확인하기](https://github.com/klaytn/klaytn-docs-ko/blob/main/docs/bapp/tutorials/count-bapp/images/tutorial-check-your-transaction.gif)

After sending a transaction, you can check your transaction detail using Klaytnscope.\
Check it in `https://baobab.scope.klaytn.com/tx/${txHash}`.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://archive-ko.docs.klaytn.foundation/content/dapp/tutorials/count-dapp/5.-frontend-code-overview/5-3.-count-component.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
