简体   繁体   English

使用 React State object 作为另一个值的键

[英]Using a React State object as key to another value

I haven't been able to figure out an efficient solution to my specific problem after trying a bunch on my own, and looking at several questions on Stack Overflow, so hopefully someone can lead me in the right direction.在我自己尝试了一堆之后,我还没有找到一个有效的解决方案来解决我的具体问题,并且在 Stack Overflow 上查看了几个问题,所以希望有人能引导我朝着正确的方向前进。

I am using React.js hooks have a state object which changes state (size and color) based on two select menus and onChange handlers. I am using React.js hooks have a state object which changes state (size and color) based on two select menus and onChange handlers. On state change, in addition to setting the select menus I would like to derive an numerical ID to set for selectedVariant , in which the ID comes from different combinations of the options state object, regardless of the order in which they were selected. On state change, in addition to setting the select menus I would like to derive an numerical ID to set for selectedVariant , in which the ID comes from different combinations of the options state object, regardless of the order in which they were selected. All of the possible combinations like {color: "Blue", size: "M" } -- mapped to --> 1234 are known, in my control, and can be put in a Map, object or array etc, but I am unsure of the best way to set mapping up and respond to this changing state efficiently.所有可能的组合,如{color: "Blue", size: "M" } -- mapped to --> 1234都是已知的,在我的控制下,可以放在 Map、object 或数组等中,但我是不确定设置映射和有效响应这种变化的 state 的最佳方法。 The setup and onChange I created looks like this, and here is a simple codesandbox linked here which contains additional info to demonstrate and a playground for the below code我创建的设置和 onChange 看起来像这样,这里是一个简单的代码框,链接在这里,其中包含要演示的其他信息和下面代码的游乐场

const [options, setOptions] = useState({}); // based on this state ...
const [selectedVariant, setSelectedVariant] = useState(null); // how do I derive a value for this?
...
      <select
        value={options.size}
        onChange={e => setOptions({ ...options, size: e.target.value })}
      >
        <option value="S">S</option>
        <option value="M">M</option>
        <option value="L">L</option>
        <option value="XL">XL</option>
      </select>
      <select
        value={options.color}
        onChange={e => setOptions({ ...options, color: e.target.value })}
      >
        <option value="Blue">Blue</option>
        <option value="Gray">Gray</option>
      </select>
...

The current state could be {size: "M", color: "Blue"} or {color: "Gray", size: "XL"} etc. depending on what is currently selected and the order in which the select boxes were populated.当前的 state 可能是{size: "M", color: "Blue"}{color: "Gray", size: "XL"}等,具体取决于当前选择的内容和 select 框的填充顺序. However, I now need to derive a variant ID from the currently selected state to know which product variant is selected using the combination of those attributes.但是,我现在需要从当前选择的 state 派生一个变体 ID,以了解使用这些属性的组合选择了哪个产品变体。

Examples: {size: "M", color: "Blue"} would derive 1234 from a mapping source and then would be set as setSelectedVariant(12345) and become the new selectedVariant state.示例: {size: "M", color: "Blue"}将从映射源派生1234 ,然后设置为setSelectedVariant(12345)并成为新的selectedVariant state。

{color: "Gray", size: "XL"} (note: different order but same keys) would derive 5678 from a mapping source and then would be set as setSelectedVariant(5678) and become the new selectedVariant state. {color: "Gray", size: "XL"} (注意:不同的顺序但相同的键)将从映射源派生5678 ,然后设置为setSelectedVariant(5678)并成为新的selectedVariant state。

Update: Example Mapping: Here is a sample mapping object of what could be done to map them in order to correlate a variant to the option values.更新:示例映射:这是一个示例映射 object 可以对 map 执行哪些操作,以便将变体与选项值相关联。

{
  "variants": [
    {
      "id": 1234,
      "title": "M / Blue",
      "option_values": [
        {
          "name": "Size",
          "value": "M"
        },
        {
          "name": "Color",
          "value": "Blue"
        }
      ]
    },
    {
      "id": 5678,
      "title": "XL / Gray",
      "option_values": [
        {
          "name": "Size",
          "value": "XL"
        },
        {
          "name": "Color",
          "value": "Gray"
        }
      ]
    }
  ]
}

which would most likely result in having to do something like a js .find() each time the state changes in order to grab the variant[n].id to pass to setSelectedVariant .这很可能导致每次 state 更改时都必须执行类似 js .find()的操作,以便获取 variant[n].id 以传递给setSelectedVariant Is this the best way to go about it?这是go的最佳方式吗?

Would this be a good use case for useReducer ?这会是useReducer的一个很好的用例吗? I also have looked into javascript Map which allows you to set an object as a key, but I wasn't able to get it working for this scenario.我还研究了 javascript Map ,它允许您将 object 设置为密钥,但我无法让它在这种情况下工作。 I am open to suggestions on different ways to think about, but hoping someone can point me to some ideas/resources to help me.我愿意接受有关不同思考方式的建议,但希望有人能指出一些想法/资源来帮助我。

The following code takes your variants data and generates data for the selectors and a variantsByKey that can be used to look up the id of the variant based on values from the selects.以下代码获取您的变体数据并为选择器生成数据,并生成一个variantsByKey可用于根据选择的值查找变体的 id。

The variantsSelects can be used for the selects and contains an enabled value to prevent non existing combinations such as Blue / XL . variantsSelects可用于选择并包含一个启用的值以防止不存在的组合,例如Blue / XL

Here is the code, I disabled showing the console.logs but you can take the code in a project and play around with it to understand it better.这是代码,我禁止显示console.logs,但您可以将代码放入项目中并使用它来更好地理解它。

 const data = { variants: [ { id: 5, title: 'Blue', option_values: [ { name: 'Color', value: 'Blue', }, ], }, { id: 1234, title: 'M / Blue', option_values: [ { name: 'Size', value: 'M', }, { name: 'Color', value: 'Blue', }, ], }, { id: 5678, title: 'XL / Gray', option_values: [ { name: 'Size', value: 'XL', }, { name: 'Color', value: 'Gray', }, ], }, ], }; const removeKey = (object, key) => Object.entries(object).filter(([k]) => k.== key),reduce((result, [key; value]) => { result[key] = value; return result, }; {}); //special none value const NONE = 'NONE', const App = ({ data }) => { const [ selectedVariants, setSelectedVariants. ] = React;useState({}). //set the values for dropdowns const variants = React.useMemo( () => [...data.variants.map(({ option_values }) => option_values).flat(),reduce( (result, { name. value }) => result,set( name. (result.get(name) || []),concat(value) ). new Map() ),entries(). ],map(([key, values]) => [key. [..,new Set(values)]]). [data;variants] ). console:log('variants,'; variants). const variantsByKey = React.useMemo( () => new Map( data.variants,map(({ id. option_values }) => [ variants.map(([key]) => option_values.find(({ name }) => name === key) ).filter((x) => x),map(({ name: value }) => `${name}:.${value}`),join('++'), id, ]) ). [data,variants; variants] ). //selects with enabled value to disable non existant // combinations const variantsSelects = React.useMemo(() => { const optionGroup = data.variants.map( ({ option_values }) => option_values,map(({ name, value }) => [name. value]),reduce( (result, [key. value]) => result,set(key, value); new Map() ) ). const selected = Object;entries(selectedVariants). return variants,map(([key. options]) => { //selected options munus current option type const sel = selected;filter(([k]) => k,== key). return [ key, options.map((option) => [ option. optionGroup,filter((variant) => sel.every( ([key. value]) => variant.get(key) === value ) ),some((v) => v,get(key) === option); ]); ], }). }, [data,variants; selectedVariants. variants]), console;log('variants by key'. variantsByKey), console;log('selects', variantsSelects). const [variantId; setVariantId] = React.useState(). React.useEffect(() => { const variantId = variantsByKey.get( variants.map(([key]) => key):filter((key) => selectedVariants[key]):map((key) => `${key}.;${selectedVariants[key]}`);join('++') ), setVariantId(variantId), }, [selectedVariants; variants. variantsByKey]), const changeSelectedVariant = React?useCallback( (value. key) => setSelectedVariants((current) => value.== NONE. {,:,current: [key], value, }; removeKey(current: key) ). [] ), return ( <div> <h3>variant id. {variantId}</h3> {variantsSelects.map(([key, values]) => ( <label key={key}> {key} <select value={selectedVariants[key]} onChange={(e) => changeSelectedVariant(e.target,value; key) } > <option value={NONE}>Select option</option> {values;map(([value. enabled]) => ( <option value={value} name={key} key={value} disabled={,enabled} > {value} </option> ))} </select> </label> ))} </div> ). }; ReactDOM.render( <App data={data} />, document.getElementById('root') );
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script> <div id="root"></div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM