skip to Main Content

I have three pretty similar functions:

//for context there is also this part:
  const [colors, setColors] = useState(["#000000", "#ffffff"]);
// but the three functions start here:

 function updateColor(index, color) {
    const newColors = [...colors];
    newColors[index] = color;
    setColors(newColors);
  }

  function deleteColor(index) {
    const newColors = [...colors];
    newColors.splice(index, 1);
    setColors(newColors);
  }

  function duplicateColor(index) {
    const newColors = [...colors];
    newColors.splice(index, 0, newColors[index]);
    setColors(newColors);
  }

As you can see the first and third line of each of these are identical. Is there some method by which I can create a function that takes the middle line as a callback function and reproduces the first and third.

Something like:

const updateColor = functionMaker((index, color) => newColors[index]);
const deleteColor = functionMaker((index) => newColors.splice(index, 1));

I can’t quite get my head around how I would support different arguments for each, as in my example above.

3

Answers


  1. Create a function that accepts a callback and returns a function that creates newColor and delegates that along with its arguments to the callback:

    function doSomethingWithColors(callback) {
      return function() {
        const newColors = [...colors];
        callback(newColors, ...arguments);
        // or callback.apply(newColors, [index, colors]);
        return newColors;
      }
    }
    

    Try it:

    function doSomethingWithColors(callback) {
      return function() {
        const newColors = [...colors];
        callback(newColors, ...arguments);
        // or callback.apply(newColors, [index, colors]);
        return newColors;
      }
    }
    
    const updateColor = doSomethingWithColors(
      (newColors, index, color) => newColors[index] = color
    );
    
    const deleteColor = doSomethingWithColors(
      (newColors, index) => newColors.splice(index, 1)
    );
    
    const duplicateColor = doSomethingWithColors(
      (newColors, index) => newColors.splice(index, 0, newColors[index])
    );
    
    const colors = ['#000', '#f00', '#fff'];
    
    console.log(colors);
    console.log(updateColor(1, '#ff0'));
    console.log(deleteColor(1));
    console.log(duplicateColor(1));
    .as-console-wrapper {
      max-height: 100% !important;
    }
    Login or Signup to reply.
  2. you can do it like so

    const handleColors = (index, action, color = '') => {
     const newColors = [...colors];
     if (action == 'duplicate') {
        newColors.splice(index, 0, newColors[index]);
     }else if (action === 'delete') {
       newColors.splice(index, 1);
     }else {
        newColors[index] = color;
     }
        setColors(newColors);
    }
    

    then use it like so,

    handleColors(2, 'delete') // for delete
    handleColors(2, 'update', 'red') // for update
    handleColors(2, 'duplicate') // for duplicate
    
    Login or Signup to reply.
  3. One approach is to use the Strategy Pattern as shown below. However, please note that this example is not well-encapsulated, and frankly removing those two lines of code might not be worth creating the abstraction.

    function modifyColor(strategy) {
        const newColors = [...colors];
        strategy(newColors);
        setColors(newColors);
    }
    
     function updateColor(index, color) {
        modifyColor((newColors) => {
            newColors[index] = color;
        });
      }
    
      function deleteColor(index) {
        modifyColor((newColors) => {
            newColors.splice(index, 1);
        });
      }
    
      function duplicateColor(index) {
        modifyColor((newColors) => {
            newColors.splice(index, 0, newColors[index]);
        });
      }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search