1

This is probably something simple, but I just can't see what I am doing wrong.

The option is not changing when I choose a different one, but the state is being updated.

I have three components, a based on class (OrcConfig) and two function components (salvarOrcamento and orcSelect). The first one owns my logic and controls the states, the second one fetchs some data from DB and sends it to third one, where the select tag is and the list of options is being created by two map methods, the first one creates the number of selects and the second one prints the list of options inside their respective select.

So far so good, the problem is that the DOM is not being updated when I change the option, however the state is, in fact it only happens when the state is being updated, if I remove this.setState the problem vanishs, of course this is not a solution, since I need to update the state. Besides that I just can't see the relation between the state and the select, since the component is not even receiving its value, it has access just to the method.

What is missing here (or left)?

Here goes a simplified version of my app:

OrcConfig component:

class OrcConfig extends Component {

state = {
    cliente: null

}

selecionarClienteHandler = e => {
    let clienteNome = this.state.cliente;
    clienteNome = e.currentTarget.value.split(',').filter(it => it !== '').join();
    this.setState({cliente: clienteNome});
    console.log(clienteNome)
}

render () {
    return (
        <div>
            <SalvarOrcamento 
                selecionarCliente={this.selecionarClienteHandler}
            />
        </div>
    );
  }
}

SalvarOrcamento component:

const salvarOrcamento = props => {

let [clientes, setClientes] = React.useState(null)

React.useEffect(() => {
    axios.get('/clientes.json')
        .then(res => {

            let clientesListaArr = Object.keys(res.data)
                                    .map(it => [['nome', it]])

            clientesListaArr.unshift([['nome', 'Clientes']])

            let clientesLista = clientesListaArr.map(it => Object.fromEntries(it))

            setClientes(clientes = clientesLista)
        })
        .catch(erro => console.log(erro))
}, [])

return (
    <div>
        <OrcSelect tipos={[clientes]} valorTipo={props.selecionarCliente} />
    </div>
  )
}

OrcSelect component:

const orcSelect = props => {
console.log(props.tipos)
return (
    props.tipos.map( (tipo, i) => {
        return  <select 
                    key={Math.random()} 
                    onChange={props.valorTipo} 
                    name={tipo[0].nome}>

                    {
                        tipo.map((item, index) => 
                            <option 
                                value={[item.valor, item.altura, item.nome, item.furo]} 
                                key={Math.random()} >{item.nome}
                            </option>
                        )
                    }
                </select>
    })
  )


};

This is an example of what OrcSelect is receving to map:

[[
   {nome: 'João'},
   {nome: 'Ricardo'},
   {nome: 'Alessandra'},
   {nome: 'Ana'}
]]
Berg_Durden
  • 1,531
  • 4
  • 24
  • 46
  • 2
    You're using `Math.random()` as thew key in the mapped options. Why? The point of a key is to let React identify which JSX element goes with which array entry. By using `Math.random()` there, the keys will change for each element on every render, meaning it's just as bad as having no key at all. The key should be a *unique* value that identifies the element consistently. – IceMetalPunk Feb 03 '20 at 21:38
  • 1
    Also, you don't have a value for the select list. You only set a value for the option. When you change the state for the value on the select list the component will rerender. – Train Feb 03 '20 at 21:40
  • @IceMetalPunk, hello. I understand that. This is just temporary to stop the warnings. – Berg_Durden Feb 03 '20 at 21:40
  • @Train Hi. It makes sense. Any idea how should I set this value? since there is no such property to select tag. – Berg_Durden Feb 03 '20 at 21:45
  • 1
    Sorry forgot to post the link https://stackoverflow.com/questions/28868071/onchange-event-using-react-js-for-drop-down – Train Feb 03 '20 at 22:33
  • 1
    Does this answer your question? [OnChange event using React JS for drop down](https://stackoverflow.com/questions/28868071/onchange-event-using-react-js-for-drop-down) – Train Feb 03 '20 at 22:34
  • @Train yes, I understood it and everything became very clear. But in the end I just needed to give a unique key to options as had already been said at the first comment. Thank you! – Berg_Durden Feb 04 '20 at 00:04
  • @ IceMetalPunk I just changed the keys and everything is working great. Thank you. – Berg_Durden Feb 04 '20 at 00:04
  • 1
    Is it working? Do you still want me to post an example in the answers? – Train Feb 04 '20 at 14:15
  • 1
    @Train Yes, it is working fine. The problem was just the keys. But the example post you sent already made the `select` matter very clear. Thank you very mudh. – Berg_Durden Feb 04 '20 at 17:09
  • 1
    Great, Glad it helped! – Train Feb 04 '20 at 20:28

1 Answers1

1

The problem is that when you change the state your DOM will be rerendered. To solve the problem you need to add the value property to the select assigning the value of the current option selected. Pass to your component a new attribute

Marco Moretti
  • 689
  • 4
  • 11
  • It makes sense. I am trying to do that since you answered, but I just don't get it. How could I do that without updating the state? I also passed the value as props to my component but it doesn't seem to have any effect. Sorry if these are dumb questions, but I really new on React – Berg_Durden Feb 03 '20 at 22:10
  • 1
    You need to save the e.currenttarget.value into state without mutating it. Pass this value ex this.state.clienteval to SalvarOrcamento componet than you need the props to OrcSelect component and finally in the select you need to add value property with the value passed from top. Tha value passed must be the same that you assigned to value attribute of option – Marco Moretti Feb 03 '20 at 22:15
  • 1
    I understood and did that. But in the end the problem was the `keys`. I was using `Math.random` as a provisory solution and React wasn't being able to identify what was really happening to my components. Thank you! – Berg_Durden Feb 04 '20 at 00:08