GeekyAnts / NativeBase

Mobile-first, accessible components for React Native & Web to build consistent UI across Android, iOS and Web.
https://nativebase.io/
MIT License
20.17k stars 2.39k forks source link

How do you integrate Picker & Radio Elements with redux-form and have them update correctly? #349

Closed maotora closed 7 years ago

maotora commented 7 years ago

Hi,

I'm using redux-form to handle my form states and I've been using NativeBase for cute components views. Thanks for that

Merging redux-form and Views Library is explained in redux-form here except they are using MaterialUI which i'm not using and so the problems with implementation appears.

I can use NativeBase <InputGroup /> Like

/** Outside Form class/Function whatever, but the Component holding the form **/
const renderVehicleName = ({ input, placeholder, meta: { pristine, touched, error } }) => (
    <ListItem>
        <InputGroup iconRight>
            <Icon name="ios-person" />
            <Input placeholder={placeholder} {...input} />
        </InputGroup>
    </ListItem>
);

/** Inside render **/
<Field name="vehicleName" placeholder="Vehicle Nickname" component={renderVehicleName} />

This works, but when it comes to Picker, Checkbox or Radio i don't know how <Field /> should look like.

I tried

/** Outside Form Component **/
 <Field name="selectVehicle" mode="dropdown" style={{left: 10}} component={renderVehicleSelect}>

    <Item label="Car" value="Car" />
    <Item label="Bus" value="Bus" />
    <Item label="Bajaji" value="Bajaji" />
    <Item label="Motorbike" value="Motobike" />
    <Item label="Camel" value="Camel" />

</Field>

/** Inside Form Component render() **/
const renderVehicleSelect = ({ input, label, meta: {touched, error}, children, ...custom }) => (

    <Picker {...input} selectedValue={input.value} onChange={(event, index, value) => input.onValueChange(value)} children={children} {...custom} />
);

Looks wrong? Yes, i thought so..

No errors, but it won't update or trigger anything when i select a value. Yes It opens a select box, but when i select say Camel nothing happens.

Please can you help me on this, or make an implementation of how to decorate NativeBase Form inputs with redux-form.

Thank You.

maotora commented 7 years ago

Hello hello!.. I solved this myself yeii!!

Well apparently i wasn't so wrong, but the redux-form example is web based and some fucntions have a different implementation when coming to react-native weird, not a surprise i suppose.

  1. The <Field name="selectVehicle" ... /> should be exactly as how i placed it there, No <Picker /> props is going inside <Field /> component and that's the situation in most of renderedComponents going inside <Field /> in compnent prop, unless for some specific cases as this Checkbox here .

  2. I mentioned above that some functions implementation is different in react-native and redux-form didn't explain that in it's examples but here is what i've found.

In this code sample

 const renderVehicleSelect = ({ input, label, meta: {touched, error}, children, ...custom }) => (

    <Picker {...input} selectedValue={input.value} onChange={(event, index, value) => input.onValueChange(value)} children={children} {...custom} />
);

Notice that i have an onChange={(event, index, value) => onValueChange(input.value) } which i did blindly without understanding that what redux-form was using in as onChange value was material-ui's function to trigger on change of <Select/ Picker /> component.

So it can now change to onValueChange={(event, index, value) => onChange(input.value)} we pass inside our NativeBase's <Picker onValueChange={...} /> prop there and inside we call redux-form's onChange(input.value) and pass in the input.

But and it's a big but this doesn't work! Inside the

onValueChange= {(event, index, value) => 
    { 
       console.log(value); //- logs undefined! 
       return onChange(input.value); 

    }

as explained in the comment, this returns undefined which was a release to me, so i tried replacing and turns out, in react-native the onValueChange only has two params, (value, index) no event!.

So i made it look like this and it worked!

onValueChange= {(value, index) => 
    { 
       console.log('value: ' + value + ' index: ' + index); //- logs value & index! 
       return onChange(input.value); 

    }

So this worked for me and it's been a great lesson on intergrating these libraries. I posted a gist for both files (wrong and working one) here didn't explain anything but there is also a <Checkbox /> implementation and the code is redable, someone may find it useful.

Thank you NativeBase, Peace out!

himanshu-satija commented 7 years ago

@maotora Thanks. This is really helpful.

maotora commented 7 years ago

Glad I contributed to such an awesome community!

jeantimex commented 7 years ago

Thank you so much @maotora! For people using NativeBase v2.2.0 and Redux-Form v6.8.0, here is how I setup the Field for Picker. Basically the idea is to hookup the input.value and input.onChange props properly to the Picker via Field.

<Field
    name="newLoanTerm"
    component={ renderPicker }
    iosHeader="Select one"
    mode="dropdown"
    format={ formatLoanTerm }
    parse={ parseLoanTerm }
>
    <Item label="30 Years" value="30" />
    <Item label="20 Years" value="20" />
    <Item label="10 Years" value="10" />
    <Item label="7 Years" value="7" />
</Field>

and here is the renderPicker function:

const renderPicker = ({ input: { onChange, value, ...inputProps }, children, ...pickerProps }) => (
  <Picker
    selectedValue={ value }
    onValueChange={ value => onChange(value) }
    { ...inputProps }
    { ...pickerProps }
  >
    { children }
  </Picker>
);

as you can see, we only care about onChange and value from the input prop.

At last, the format and parse functions for formatting the selected value to string and save the selected value to number in the redux store:

const formatLoanTerm = value => value.toString();
const parseLoanTerm = value => parseInt(value);

Note, if you store the value as string (e.g. "10") in the redux-form store, then you don't need to set the format and parse props.

If you are confused about the format and parse functions, see http://redux-form.com/6.8.0/docs/ValueLifecycle.md/.

Hope that helps.

luklapp commented 7 years ago

@jeantimex: I have a problem with your solution (code in the referenced ticket): The store is updated correctly, but the picker shows the wrong (first) option. Any idea why?

jeantimex commented 7 years ago

@luklapp, I see you are using redux-form/immutable, what if you try redux-form without immutable, would that work?

luklapp commented 7 years ago

@jeantimex I'm using immutablejs in the whole application, so it would be good to get it working with redux-form/immutable!

michaelnagy commented 7 years ago

I'm getting the same issue without immutable.js. After some updates in the picker value, the store starts to skip some update value. Here is my code:

` {categories.map(val =>

)} ` ` onChange(value)} > { children } `
luklapp commented 7 years ago

@michaelnagy I found a solution without using the Field component, you can find it here: https://github.com/erikras/redux-form/issues/3243

donnes commented 7 years ago

Hello @maotora The checkbox gist example it's no longer available. You have this example yet?

Thank you!

maotora commented 7 years ago

Hi @donnes

Really sorry man, I accidentally deleted all my gists! I will recreate it if it is really needed as I can see there are some better suggestions on this thread already.

Or you can explain your issue a little better for all subscribers to understand it and help.

donnes commented 7 years ago

@maotora

I think it's not a exactly a issue. I just don't understood how implements the Redux Form with Radio and Checkbox because this components don't have the value property and the Field component from Redux Form requires it. I don't know how get the value from selected Radio/Checkbox exactly because they don't have this property.

Another question is how you implemented Radio Groups (Just a single radio can be selected if they are at same group)?

Sorry if this question sounds much simple. Thank you!

nonameolsson commented 7 years ago

@donnes I'm struggling with using Radio Buttons myself. Any progress?

maotora commented 7 years ago

Hey guys, I thought I should re-create the gist.

Link: here

Here is how I did it back in 2016 with "native-base": "^0.5.15" & "redux-form": "^6.3.2". @donnes , @nonameolsson .

Goodluck!

donnes commented 7 years ago

Wow! Thank you very much @maotora It will help me a lot!

maotora commented 7 years ago

@donnes Thanks man. 👍

nonameolsson commented 7 years ago

Thanks!! Is it also possible to integrate with Radio Buttons? I couldn't see how to so that. All help appreciated. On Sat, 2 Sep 2017 at 11:41, ᕙ(⇀‸↼‶)ᕗ notifications@github.com wrote:

Closed #349 https://github.com/GeekyAnts/NativeBase/issues/349.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/GeekyAnts/NativeBase/issues/349#event-1232382210, or mute the thread https://github.com/notifications/unsubscribe-auth/ABbIGjp1MfItSSJBVSrRW65GZDXT1szBks5seYUpgaJpZM4LHvEi .

-- Andreas Olsson (+46)70 - 090 42 72

maotora commented 7 years ago

I'm pretty sure it's simple @nonameolsson If you check on my gist from this line for the checkbox example and check nativebase Radio Buttons api here swap checkbox's checked with Radio button's selected attr.

Well, Theoretically

nonameolsson commented 7 years ago

@maotora Thanks for your help! Your Gist helped me. The thing is that RadioButtons only can have one selected, and checkboxes can have many. So I created a component that manage the state, and renders the radio buttons.

Here is my Gist: https://gist.github.com/nonameolsson/88b4f2349719f4657ae659d76e496d28

I hope it can help someone else. And if you have any idea how to improve the code I would appreciate it!

tinashe96 commented 6 years ago

@jeantimex I have used your solution. Everything seems to be working except the default selectedValue is undefined. If I don't use the picker, the default value is not taken. onValueChange works as expected. tested on android.

`<Field name={'gender'} component={renderGenderPicker} iosHeader="Select one" mode="dropdown"

`

`const renderGenderPicker = ({ input: { onChange, value, ...inputProps }, children, ...pickerProps }) => ( <Picker selectedValue={value} onValueChange={value => onChange(value)} {...inputProps} {...pickerProps}

{ children } );`

nazrdogan commented 6 years ago

@nonameolsson I got idea from you. and created new component. Here is my gist: https://gist.github.com/nazrdogan/b57f292d9f5c115f254094e3d13def17

adjieindrawan commented 6 years ago

@maotora still confuse with radio box, can help me with some example? Thanks