Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
143 views
in Technique[技术] by (71.8m points)

javascript - React, working with select component with objects

Im new to react and I have a question about select component of material ui.

The thing is like this, I have a funcionality that is for creating and editing an User, this User is an object, it has primary key and some data, between this data there is a relation with other object that is a role, so in this case I use a Select component to select the role.

So, I have the role list that I bring from the backend:

const [rolList, setRolList] = React.useState([]);

const searchRoles = async () => {
    try {
      setRolList(await api.post('/v1/roles/buscar', filtroRol));
    } catch (error) {
      snackbar.showMessage(error, "error");
    }
  }

And the select component that is inside a formik:

              <Mui.Select 
                    label="Role"    
                    value={values.usuRolPk}
                    onChange={(opt) =>{handleChange(opt);
                    }}          
                    >
                      <Mui.MenuItem disabled key={0} value=''>
                        Select role
                      </Mui.MenuItem>
                    {rolList.map((e) => {
                        return <Mui.MenuItem key={e.rolPk} value={e.rolPk}>{e.rolName}</Mui.MenuItem>;
                    })}
                  </Mui.Select>

As you can see, for the value of the select I use the pk of role, so when the user is persisted I have to search in the list of roles and atach the selected object to the users object and send it to the backend.

Something like this (usuRolPk is the value of the select, usuRol is the relation with object role):

const save = async (values) => {
    try {      
      
      if(values.usuRolPk==null){
        values.usrRole=null;
      }else{      
        values.usrRole=rolList.filter(element=>''+element.rolPk==values.usuRolPk)[0];
      }  
     ...

      if (values.usrPk == null) {
        await api.post('/v1/users', values);
      } else {
        await api.put('/v1/users/' + values.usrPk, values);
      }
      handleClose();
      snackbar.showMessage("GUARDADO_CORRECTO", "success")
    } catch (error) {
      snackbar.showMessage(error, 'error');
    }
    return;
  }

The thing is, I want to skip that last step of having to search in the list of roles with the selected Pk. Is there a way of working just with the object as the selected value instead of the pk? I tried just changing the value to have the whole object like this:

                  <Mui.Select 
                        label="role"    
                        value={values.usuRol}
                        onChange={(opt) =>{handleChange(opt);
                        }}          
                        >
                          <Mui.MenuItem disabled key={0} value=''>
                            Select role
                          </Mui.MenuItem>
                        {rolList.map((e) => {
                            return <Mui.MenuItem key={e.rolPk} value={e}>{e.rolName}</Mui.MenuItem>;
                        })}
                      </Mui.Select>

This works just when Im creating a new object, but when I try to edit an object that already exists and already has a role, when I pass the role to the select It says something like I initialize the Select with a value that doesnt exist in the list of roles.

Is there a way to achieve this?

Thanks!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Per conversation in the comments on the question:

I'm doing this with a normal select and options purely for convenience, but you can replace them easily enough with their mui equivalents:

import React, { useState, useEffect, useCallback } from 'react';

const SomeComponent = () => {
  const [list, setList] = useState({}); // { "1": someObjWithId1, etc }
  const [selected, setSelected] = useState();
  useEffect(() => {
    const getList = async () => {
      const resp = await fetch('/some/url'); // get object list from backend
      const data = await resp.json();
      setList(data);
    };

    if (!list.length) getList();
  }, []);

  const handler = useCallback((evt) => {
    setSelected(list[evt.target.value]);
  }, [list, setSelected]);

  return (
    <select onChange={handler}>
      {Object.entries(list).map(([id, obj]) => selected && id === selected.id
        ? <option selected key={id} value={id}>{obj.text}</option>
        : <option key={id} value={id}>{obj.text}</option>
      )}
    </select>
  );
};

The component will render a select element with the options once they've been passed from the backend. The change handler will update the state with the entire object (keyed by the id/value) selected. In real life you'd likely have the state in a parent form component and pass it with the setter through props, but you get the idea.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...