Josh
Josh

Reputation: 1235

React/Redux Component, need to populate a certain number of fields based on dropdown selection

This is similar to a previous question I had asked before, but I have since moved my project architecture around to include Redux.

I have a component that dynamically generates it's dropdown contents based on a data response that's currently coming from within the app.

One of the dropdowns features a selection of none, 1, 5, 13 items. Based on which number the user selects a second section should dynamically render showing that many rows with their own dropdown.

The problem I'm having is that I originally controlled this behavior by using local state and react hooks. Since then the dropdown options have moved to the store and I can no longer add the the onChange behavior to each unique option now that they are being generated as part of a map function.

Here's the original CodeSandbox for local state:

Edit 56796511

And this is what my current select drop down looks like from my application now that it's reading from the store:

<Select
onChange={e => {
  props.updateCart(
    {
      lineOne: 'Thing#1',
      lineTwo: 'addOns',
      itemThree: 'Thing#3',
      item:
        parent.configurationItems[parseInt(e.target.value, 10)]
    },
  )
}}
>
{parent.configurationItems.map((obj, idx) => {
  const { id, name } = obj
  return (
    <option
      key={id}
      value={idx}
    >
      {name}
    </option>
  )
})}
</Select>
</Col>

Upvotes: 0

Views: 79

Answers (1)

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

Made a sandbox for you that accomplishes what you're trying to do with redux: https://codesandbox.io/s/bj984

This is your updated ConfigurationOptions component, see sandbox for the rest of the code :)

import React, { useState, useEffect } from "react";
import styled from "styled-components";
import "antd/dist/antd.css";
import { Row, Col } from "antd";
import AntCollapse from "./CustomCollapse";
import { connect } from "react-redux";
import { setNumberInRedux } from "./configActions";

const Button = styled.button`
  color: white;
  background-color: #0076de;
  border-radius: 5px;
`;

const ConfigurationOptions = ({ config, setNumberInRedux }) => {
  const [configNumber, setConfigNumber] = useState(0);
  const [configList, setConfigList] = useState([]);

  const setConfig = number => {
    setConfigNumber(number); //change component-state
    setNumberInRedux(number); //call action-creator to update redux
  };

  //will only run when there is a change to the redux state
  useEffect(() => {
    const number = config.number;
    //set list when redux state number changes
    let newArray = new Array(parseInt(number, 10)).fill(0);
    setConfigList(newArray);
  }, [config]);

  const setList = (number, index) => {
    setConfigList(prevState => {
      let newState = [...prevState];
      newState[index] = parseInt(number, 10);
      return newState;
    });
  };

  return (
    <AntCollapse header="configuration test">
      <div>
        <h1>Section Header</h1>
        <Row>
          <Col span={4} offset={20}>
            <Button type="submit">Apply to All</Button>
          </Col>
        </Row>
        <Row>
          <Col span={12}>
            <h3>Config Section #1</h3>
          </Col>
        </Row>
        <Row>
          <Col span={12}>
            <p>How many do you need?</p>
          </Col>
          <Col span={4} offset={8}>
            <select
              value={configNumber}
              onChange={e => setConfig(e.target.value)}
            >
              <option value={0}>None</option>
              <option value={1}>1 Option</option>
              <option value={5}>5 Options</option>
              <option value={13}>13 Options</option>
            </select>
          </Col>
        </Row>
        <Row>
          <Col span={12}>
            <h3>Conditional Config Section</h3>
          </Col>
        </Row>
        {configList.map((num, i) => (
          <Row key={i.toString()}>
            <Col span={12}>
              <p>Option Configuration Dropdown</p>
            </Col>
            <Col span={4} offset={8}>
              <select value={num} onChange={e => setList(e.target.value, i)}>
                <option value={0}>Default</option>
                <option value={1}>Add #1</option>
                <option value={2}>Add #2</option>
                <option value={3}>Add #3</option>
              </select>
            </Col>
          </Row>
        ))}
      </div>
    </AntCollapse>
  );
};

const mapStateToProps = state => {
  return {
    config: state.config
  };
};

const mapDispatchToProps = dispatch => {
  return {
    setNumberInRedux: number => {
      dispatch(setNumberInRedux(number));
    }
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(ConfigurationOptions);

Upvotes: 1

Related Questions