skip to Main Content

I have a state with an array of objects:

const [Value, setValue] = useState([{ Width: null, Length: null }, { Width: null, Length: null }])

And also, I have a component from which I want to get the value for Value using setValue.

Here is the code:

const [Value, setValue] = useState([{ Width: null, Length: null }, { Width: null, Length: null }])

export function SimpleComponent({ Width, setWidth, Length, setLength }) {
  return (
    <>
      <input
        type="number"
        value={Width || ""}
        onChange={event => setWidth(event.target.value)}
      />
      <input
        type="number"
        value={Length || ""}
        onChange={event => setLength(event.target.value)}
      />
    </>
)}

{Value.map((item, i) => {
    return (
      <div key={i}>
        <SimpleComponent
          Width={item.Width}
          setWidth={???}
          Length={item.Length}
          setLength={???}
        />
      </div>
    )
  })
}

And I need to specify the Width and Length value for the current component SimpleComponent in the attributes setWidth and setLength, specified with "???" signs in the code.

I tried to solve this in some ways, but without success.

Please help!

3

Answers


  1. Either you can write 2 functions, one for length and one for width

    {Value.map((item, i) => {
        return (
          <div key={i}>
            <SimpleComponent
              Width={item.Width}
              Length={item.Length}
              setWidth={(newValue) => {
                setValue([
                    ...Value.slice(0, i),
                    { ...Value[i], width: newValue },
                    ...Value.slice(i+1)
                ])
              }}
              setLength={(newValue) => {
                setValue([
                  ...Value.slice(0, i),
                  { ...Value[i], length: newValue },
                  ...Value.slice(i+1)
                ])
              }}
            />
          </div>
        )
      })
    }

    Or you can combine these into one single function

    setDimension=(newValue, i, property) => {
      setValue([
        ...Value.slice(0, i),
        { ...Value[i], [property]: newValue },
        ...Value.slice(i+1)
      ])
    }
     
    {Value.map((item, i) => {
        return (
          <div key={i}>
            <SimpleComponent
              Width={item.Width}
              setWidth={(newValue) => setDimension(newValue, i, "width")}
              Length={item.Length}
              setLength={(newValue) => setDimension(newValue, i, "length")}
            />
          </div>
        )
      })
    }
    Login or Signup to reply.
  2. You need to define function that, when a new width should be set at index i in the Value array, copies the previous array and replaces the element at index i with a new entry.

    
    const setWidthAtIndex = (value, i) = setValue(
        value => value?.map(
            (width, j) => i === j ? {width: value} : width)
    );
    
    {Value.map((item, i) => {
        return (
          <div key={i}>
            <SimpleComponent
              Width={item.width}
              setWidth={e => setWidthAtIndex(e, i)}
            />
          </div>
        )
      })
    }
    
    Login or Signup to reply.
  3. You can define your functions like this:

    const setWidth = (newWidth: number, index?: number) => {
      setValue(current =>
        current.map((currentValue, j) => {
          if (!index || index === j) {
            return { ...currentValue, Width: newWidth }
          }
    
          return currentValue
        })
      )
    }
    
    const setLength = (newLength: number, index?: number) => {
      setValue(current =>
        current.map((currentValue, j) => {
          if (!index || index === j) {
            return { ...currentValue, Length: newLength }
          }
    
          return currentValue
        })
      )
    }
    

    Then render components like this:

    {Value.map((item, i) => {
      return (
        <div key={i}>
          <SimpleComponent
            Width={item.Width}
            setWidth={(newWidth) => setWidth(newWidth, i)}
            Length={item.Length}
            setLength={(newLength) => setLength(newLength, i)}
          />
        </div>
      );
    })}
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search