0

I want to make a counter app with increment, decrement and add counter button. But add counter function is not working. It's showing this error:

Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...?

i have already tried enclosing it in tags,still its not working.

import React,{Component} from 'react';
import './App.css';


export class App extends Component {
  state={
    count:0,
  }

  increment=()=>{
    this.setState({ count: this.state.count + 1 });
  }

  decrement=()=>{
    this.setState({ count: this.state.count - 1 });
  }

  addCounter=()=>{

        <span><button onClick={this.increment}>+</button></span>

         <span>{this.state.count}</span>
         <span><button onClick={this.decrement}>-</button></span>


  }

  render() {
    return (
      <div className="App">


      <button onClick={this.addCounter}>Add Counter</button>
      </div>



    )
  }
}




export default App;

add counter function should add another counter just below the previous counter.

norbitrial
  • 14,716
  • 7
  • 32
  • 59
  • You have to have a single root for any JSX element. The easiest way to get there is to wrap your elements with (newer versions of react will also support <> > as syntactic sugar). In your cast, you need to do so for the elements returned in addCounter. Note that this was answered before, e.g.: https://stackoverflow.com/questions/31284169/parse-error-adjacent-jsx-elements-must-be-wrapped-in-an-enclosing-tag – Moshe Jonathan Gordon Radian Oct 10 '19 at 06:28
  • 1
    Your "counter" needs to be a react component with its own state, what you have there will have each "counter" you add use the same component state from `App`. – Drew Reese Oct 10 '19 at 06:31

5 Answers5

2

Basically extract a Counter component.

Then have your App maintain a list of Counter components.

// Counter Component
export class Counter extends React.Component {
  state = {
    count:0,
  }

  increment=()=>{
    this.setState({ count: this.state.count + 1 });
  }

  decrement=()=>{
    this.setState({ count: this.state.count - 1 });
  }

  render() {
    return (
      <div>
        <span><button onClick={this.increment}>+</button></span>
        <span>{this.state.count}</span>
        <span><button onClick={this.decrement}>-</button></span>
      </div>
    );
  }
}
// App Component
export class App extends React.Component {
  state = {
    counters: [], // additional state for Counter components
  }

  addCounter = () => {
    this.setState({
      counters: [
        ...this.state.counters,
        Counter
      ]
    })
  }

  render() {
    return (
      <div className="App">
        <button onClick={this.addCounter}>Add Counter</button>
        { this.state.counters.map((Counter, index) => (
           <Counter key={index} />)
        )}
      </div>
    )
  }
}

Demo

Joseph D.
  • 11,804
  • 3
  • 34
  • 67
0

You are just adding more spans and button but refering to the same counter.

state={
  i : 0,
  count:0,
}
var newCount="counter"+this.state.i;
this.setState({
 i : this.state.i+1,
})
this.setState({
  count: {
     ...this.state.count,
     newCount: 0
  }
});

So with this you add a new counter with a progresive autoincrement number.

P4uB0rd4
  • 175
  • 5
0

You have to add another functional Component instead of adding JSX. DEMO

import React from 'react';
const counter = (props) => {
   return (
      <div>
         <span><button onClick={() => props.increment(props.index)}>+</button></span>
             <span>{props.count}</span>
         <span><button onClick={() => props.decrement(props.index)}>-</button></span>
      </div>
   )
}    
export default counter; 

And your main App component

import React, {Component} from 'react';
import Counter from './Counter';
import './App.css';


export class App extends Component {
  state={
     counters: []
  }

  valueChanger = (index, inc) => {
     this.setState((prevState) => {
        const counters = prevState.counters.slice();
        counters[index] += inc; 
        return {
            counters: counters
        }
     });
  }

  increment=(index)=>{
     this.valueChanger(index, 1);
  }

  decrement=(index)=>{
     this.valueChanger(index, -1);
  }

  addCounter=()=>{
     this.setState((prevState) => { 
        return { counters: [...prevState.counters, 0] }
     });
  }

  render() {
    let counterElems = this.state.counters.map((c, index) => {
       return <Counter key={index} index={index} increment={this.increment} decrement={this.decrement} count={c} />
    });

    return (
      <div className="App">
          {counterElems}
          <button onClick={this.addCounter}>Add Counter</button>
      </div>
    )
  }
}

export default App;
Kishor
  • 2,659
  • 4
  • 16
  • 34
0

Your "counter" needs to be a react component with its own state, what you have there will have each "counter" you add use the same component state from App. You also do not save the returned JSX to then render anywhere.

const Counter = () => {
  const [count, setCount] = useState(0);

  return (
    <div> // <-- React components can return only a single node*
      <span>
        <button onClick={() => setCount(count + 1)}>+</button>
      </span>
      <span>{count}</span>
      <span>
        <button onClick={() => setCount(count - 1)}>-</button>
      </span>
    </div>
  );
};

class App extends Component {
  state = {
    counters: []
  };

  addCounter = () => {
    this.setState(prevState => ({
      counters: [...prevState.counters, <Counter />]
    }));
  };

  render() {
    return (
      <div>
        <button onClick={this.addCounter}>Add Counter</button>
        {this.state.counters}
      </div>
    );
  }
}

Edit frosty-monad-bc71e

* React render lifecycle function can render arrays.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
0

I think it is what you want to do.

const { useState } = React;
function App(){
  const [counter, setCounter] = useState([]);
  
  function addCounter(){
    setCounter(counter.concat({id: counter.length, count: 0}));
  }
  function increase(id){
    setCounter(counter.map(el=>{
      if(el.id === id){
        el.count++;
      }
      return el;
    }));
  }
  function decrease(id){
    setCounter(counter.map(el=>{
      if(el.id === id){
        el.count--;
      }
      return el;
    }));
  }
  return (
    <div className="App">
      <button onClick={addCounter}>Add Counter</button>
      {
        counter.map(el=>{
          return(
            <div key={el.id}>
              <span>Counter #{el.id}</span>
              <div>
                <button onClick={()=>{increase(el.id)}}>+</button>
                <span>{el.count}</span>
                <button onClick={()=>{decrease(el.id)}}>-</button>
              </div>
            </div>
          )
        })
      }
    </div>
  )
}

ReactDOM.render(
  <App />, document.getElementById('root')
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root"></div>
kyun
  • 9,710
  • 9
  • 31
  • 66