Home > Mobile >  React: How to change props values
React: How to change props values

Time:09-02

In my code, I replace these values

const [items, setItem] = useState<string[]>([]);
const [value, setValue] = useState('')
const [error, setValue]= useState('')

to this

type Props = { items?: string[], value?: string, error?: string }

and then change the following setItem, setValue, setValue which causes the following error

enter image description here

import React, { useRef, useState } from "react";
import ReactDOM from "react-dom";
import Chip from "@material-ui/core/Chip";
import TextField from "@material-ui/core/TextField";

type Props = {
  items?: string[],
  value?: string,
  error?: string
}

export const TagActions = (props:Props) => {
    const { items, value, error } = props;

    // const [items, setItem] = useState<string[]>([]);
    // const [value, setValue] = useState('')
    // const [error, setError]= useState('')
    
    const divRef = useRef<HTMLDivElement>(null)

    const handleDelete = (item:any) => {
        console.log("handleDelete", item)
        const result = items?.filter(i => i !== item)
        setItem(result)
      };
    
    const handleItemEdit = (item:any) =>{
        console.log("handleItemEdit", item)
        const result = items?.filter(i => i !== item)
        
        items = result    // setItem(result)
        value = item     // setValue(item)

        console.log("value", value)
        
    };

    const handleKeyDown = (evt:any) => {
        if (["Enter", "Tab", ","].includes(evt.key)) {
          evt.preventDefault();

          var test = value?.trim();
    
          if (test && isValid(test)) {
            items?.push(test)
            setValue("")
           
          }
        }
    };

    const isValid = (email:any)=> {
        let error = null;
    
        if (isInList(email)) {
          error = `${email} has already been added.`;
        }
    
        if (!isEmail(email)) {
          error = `${email} is not a valid email address.`;
        }
    
        if (error) {
            setError(error);
    
          return false;
        }
    
        return true;
    }

    const isInList = (email:any)=> {
        return items?.includes(email);
      }
    
    const isEmail = (email:any)=> {
        return /[\w\d\.-] @[\w\d\.-] \.[\w\d\.-] /.test(email);
    }

    const handleChange = (evt:any) => {
        setValue(evt.target.value)
        // setError("")
        
    };

    const handlePaste = (evt:any) => {
        evt.preventDefault();
    
        var paste = evt.clipboardData.getData("text");
        var emails = paste.match(/[\w\d\.-] @[\w\d\.-] \.[\w\d\.-] /g);
    
        if (emails) {
          var toBeAdded = emails.filter((email:any) => !isInList(email));
            
            setItem(toBeAdded)
        
        }
    };
    


    return (
        <>
          <div>
          <TextField id="outlined-basic" variant="outlined"
          InputProps={{
            startAdornment: items?.map(item => (
              <Chip
                key={item}
                tabIndex={-1}
                label={item}
                onDelete={() => handleDelete(item)}
                onClick={() => handleItemEdit(item)}
              />
            )),
  
          }}
            ref={divRef}
            value={value}
            placeholder="Type or paste email addresses and press `Enter`..."
            onKeyDown={(e) => handleKeyDown(e)}
            onChange={(e) => handleChange(e)}
            onPaste={(e) => handlePaste(e)}
          />
          </div>
  
          {error && <p className="error">{error}</p>}
        </>
      );
}

I am a beginner in react typescript, so I don't know how to fix this, Please give me a solution to fix this problem

CodePudding user response:

While changing const to let may fix immediate errors in the console, I doubt this will give you the behaviour that you desire.

The main issue here is that you are mutating the value of props, which in general you should never do. Props are used to pass stateful data down from a parent to a child component. If you wish to update the state of this data from the child component, you should pass an update function using props as well. Below gives an example of what I mean by this by implementing the delete item function (no typescript, but hopefully it gets the idea across):

const ParentComponent = () => {
  const [items, setItems] = useState(["item1", "item2", "item3"])
  
  const deleteItem = (itemToDelete) => {
    //here we use the functional update form of setState which is good practise when the new state depends on the old state
    setItems((items) => items.filter((item) => item!==itemToDelete))
  }
  
  return <ChildComponent items={items}, onDeleteItem={deleteItem} />
}
const ChildComponent = ({items, onDeleteItem}) => {

  //e.g. to delete item2 call
  onDeleteItem("item2")
}

This is one of the more confusing patterns in React, but it is very important to get your head around. Only the component where state is declared should actually be updating that state - as it is the only place where you have access to the setState function.

CodePudding user response:

The solution is in the error message, you can't assign a variable to a constant so your problem is here

const { items, value, error } = props;

items and value are declared to be constant, this prevents them from being reassigned. Switch them to let so they can be reassigned

let { items, value } = props;
const { error } = props;

the reason I am not switching error to let is because you never re-assign it so it can stay a const.

  • Related