martikol
martikol

Reputation: 29

passing and returning useState in react

Yeah, so I'm trying to learn react and I'm doing a simple project to understand it better.

basically what I'm trying to do is use useState from one file and let it be changed by an onClick function on the other file like so:

list.js

export const List= [
{id:1, obj:'item1'},
{id:2, obj:'item2'},
{id:3, obj:'item3'},
{id:4, obj:'item4'},] ;

index.js

import React,{useState} from 'react'
import {List} from './list'
import ItemList from './ItemList'
function Items(){
      const [items,setItems] = React.useState(List);
return (
    <>
        <h1>{items.length} Items in total</h1>
        {items.map((itemArr)=>{
       
            return (
                <ItemList {...itemArr}/>
                
            )
        })}

    </>   
)
    }
    ReactDom.render(<Items />,document.getElementById('root')
)

ItemList.js

import React from 'react'

function ItemList(props) {
    const {id,obj} = props;
    const removeItem = (id) =>{
     //Code Here
    }
    return (
       <div>
            <h3>{id}</h3>
            <h4>{obj}</h4>           
            <button onClick={()=> removeItem(id)}>Remove</button>
        </div>
    )
}
export default ItemList

What I want to do is when I click the button, the removeItem function will remove whatever the item is with the id and use .filter. But the problem i'm facing is that I can't seem to find out on how I can call and return something to setItems so that I can change the value. And I can't find out a way to pass setItem to itemList.js.

Upvotes: 1

Views: 92

Answers (2)

Drew Reese
Drew Reese

Reputation: 202751

You can pass setItems as a prop to ItemList

function Items(){
  const [items,setItems] = React.useState(List);

  return (
    <>
      <h1>{items.length} Items in total</h1>
      {items.map((itemArr) => {
        return (
          <ItemList {...itemArr} setItems={setItems} /> // <-- pass callback
        )
      })}
    </>
  )
}

And consume off props in child. Use a functional state update to access the previous state, filtering it and returning the next state.

function ItemList(props) {
  const { id, obj, setItems } = props; // <-- destructure from props

  const removeItem = (id) =>{
    setItems(items => items.filter(item => item.id !== id)) // <-- update state
  }

  return (
    <div>
      <h3>{id}</h3>
      <h4>{obj}</h4>           
      <button onClick={() => removeItem(id)}>Remove</button>
    </div>
  )
}

Generally though it is preferable to let the component owning the state also maintain all the functions that operate on that state. In other words, you should define the removeHandler in the parent and pass a reference to it. This allows and makes it the parent component's responsibility to maintain the state invariant, not any child component's responsibility.

function Items(){
  const [items,setItems] = React.useState(List);

  const removeItem = (id) =>{
    setItems(items => items.filter(item => item.id !== id))
  }

  return (
    <>
      <h1>{items.length} Items in total</h1>
      {items.map((itemArr) => {
        return (
          <ItemList {...itemArr} removeItem={removeItem} />
        )
      })}
    </>
  )
}

function ItemList(props) {
  const { id, obj, removeItem } = props;

  return (
    <div>
      <h3>{id}</h3>
      <h4>{obj}</h4>           
      <button onClick={() => removeItem(id)}>Remove</button>
    </div>
  )
}

Upvotes: 1

Rahul Arora
Rahul Arora

Reputation: 131

You need to pass a callback function to the from Items Component to ItemList Component.

index.js

import React,{useState} from 'react'
import {List} from './list'
import ItemList from './ItemList'
function Items(){
      const [items,setItems] = React.useState(List);

onClickHandler(id){
   .... 
    change state
   ....
}
return (
    <>
        <h1>{items.length} Items in total</h1>
        {items.map((itemArr)=>{
       
            return (
                <ItemList onClickHandler={onClickHandler} {...itemArr}/>
                
            )
        })}

    </>   
)
    }
    ReactDom.render(<Items />,document.getElementById('root')
)

ItemList.js

import React from 'react'

function ItemList(props) {
    const {id,obj,onClickHandler} = props;
    return (
       <div>
            <h3>{id}</h3>
            <h4>{obj}</h4>           
            <button onClick={()=> onClickHandler(id)}>Remove</button>
        </div>
    )
}
export default ItemList

In React data can be passed in one direction only, so to update the data in the parent component from the child component you need to pass functions as props

Upvotes: 0

Related Questions