React-native Input HOC for redux-form loses focus after type a symbol - react-native

I'm trying to use redux-form, but, as I read, I need HOC for Input field to replace onTextChange to onChange. I have:
import React from 'react';
import {Input} from 'native-base';
export default function InputField(props) {
const { input, ...inputProps } = props;
return (
<Input
{...inputProps}
onChangeText={input.onChange}
onBlur={input.onBlur}
onFocus={input.onFocus}
value={input.value}
/>
);
};
and use it in my form:
<Item style={{marginTop: 10, width: "100%"}}>
<Field name="login" component={(props) => {
return (
<InputField {...props} keyboardType="email-address" placeholder='E-mail' />
)
}}/>
</Item>
But every time I type key, the field loses focus. Some "experts" recommend use focus() function. But what if I edit text in the middle of it?
Any solutions? Or maybe native-base have compatible textfield component?

It is strange, but it works ))
function InputFieldEmail(props) {
return <InputField {...props} keyboardType="email-address" placeholder='E-mail' />;
}
and use it instead arrow functions
<Field name="login" component={InputFieldEmail}/>
I think it's strange )

You must provide the InputField component as a prop so that its value is constant or put it outside the Item component, when it is inside another, every time the state of the upper level is updated, the lower level is forced to return. to start.
If your Input is inside an Item you are probably using a FlatList and your goal is to put it in the header.
You can try something like this:
<View style={{marginTop: 10, width: "100%"}}>
<Field name="login" component={(props) => {
return (
<InputField {...props} keyboardType="email-address" placeholder='E-mail' />
)
}}/>
</View>
<FlatList
ListHeaderComponent={() => {
<Item>
</Item>
}}
/>
Remember to put the styles that were in Item in View.

Related

How to pass state into Parent?

I am fairly new to React, and I am making a small single page application, and I am trying to figure out how to pass the employee ID to the parent.
So there is an issue here, which I already know.... but trying to figure out a solution.
There will be 3 screens first starts with the ID.
When I have it as the code listed below, everytime I type, the state rerenders, however it DOES work. It just really annoying to type.
import React, { useState } from 'react';
import {
Container,
Header,
Title,
Body,
Content,
Item,
Input,
Icon,
Text,
View,
} from 'native-base';
export default function App() {
const [id, setId] = useState('');
const IdScreen = () => {
return (
<View>
<Text>Enter your Employee ID</Text>
<Item rounded style={styles.textBox}>
<Icon type='Ionicons' name='person' style={{ fontSize: 30 }} />
<Input
onChangeText={(text) => {
setId(text);
}}
value={id}
/>
</Item>
</View>
);
};
return (
<Container>
<Header>
<Body>
<Title>Employee Enroll</Title>
</Body>
</Header>
<Content>
<IdScreen />
</Content>
</Container>
);
}
If I make this change... the typing part is fine, but when I go to push this to the API, it wont be readable.
const IdScreen = () => {
const [id, setId] = useState('');
return (
<View>
<Text>Enter your Employee ID</Text>
<Item rounded style={styles.textBox}>
<Icon type='Ionicons' name='person' style={{ fontSize: 30 }} />
<Input
onChangeText={(text) => {
setId(text);
}}
value={id}
/>
</Item>
</View>
);
};
I am looking for a way to type in the person ID, then save that state to the main function so that I can use that variable later.
I just don't know how to do that.
First of all take the IdScreen component out of the App component (You should have your components in different files), then if you want to pass the id from IdScreen to App you need to lift up the state. In order to do that you will need to the following:
Put this const [id, setId] = useState(''); only in the App component, then pass the setId function to the IdScreen component as a props, like this:
<IdScreen id={id} setId={setId} />
Then in your IdScreen component you can use the setter function and the value as props, like this:
props.id and props.setId

Display Field in Edit Form

Currently, if I try to place a Field into an Edit form, the field doesn't display at all. There is no errors in the console or the terminal about why it wont.
Example:
<Edit undoable={false} {...props}>
<SimpleForm>
<FormRow>
<TextField source="id"/>
<TextField source="name"/>
</FormRow>
</SimpleForm>
</Edit>
will not display either of these on the page load, it will simply be blank.
Is there any way to use fields in the Edit form?
You need to pass in the record prop (and basePath if its a reference).
The Edit component does not get the record prop so create a form component and it will get passed the record as a prop
eg.
const ProjectEdit: FC<EditComponentProps> = props => {
const classes = useStyles();
return (
<RA.Edit {...props} title={<ProjectTitle />}>
<RA.SimpleForm>
<ProjectForm />
</RA.SimpleForm>
</RA.Edit>
);
};
export const ProjectForm = (props: any) => {
return (
<Box flex={1} mr={{ md: 0, lg: '1em' }}>
<RA.TextInput source="name" fullWidth={true} />
<Typography variant="h6" gutterBottom>
Tasks
</Typography>
<RA.TextField
source="name"
fullWidth={true}
record={props.record}
/>
<RA.ReferenceManyField
label="Tasks"
reference="Task"
target="projectId"
fullWidth={true}
record={props.record}
basePath="/Task"
>
<RA.SingleFieldList fullWidth={true}>
<RA.ChipField source="name" fullWidth={true} />
</RA.SingleFieldList>
</RA.ReferenceManyField>
</Box>
);
};

How to prevent flatlist header or footer from re-render in reactnative

I put an input field in the footer of flatlist but when i try to type anything it dismiss the keyboard automatically because of the re-render of the flatlist footer..
I tried to nest the flatlist from Scrollview but this brings warning..
How can i stop the footer from being re-rendered? can i fix this without nest the flatlist from Scrollview?
<FlatList
ListHeaderComponent={() => (
<View style={styles.discountContainer}>
<Text style={[styles.buttonText, { letterSpacing: 3 }]}>
10% DISCOUNT ON 8 COURSES
</Text>
</View>
)}
numColumns={2}
data={data}
renderItem={({ item }) => (
<View>
<SingleProduct item={item} />
</View>
)}
ListFooterComponent={() => (
<View>
<View style={styles.couponContainer}>
<Input
placeholder='Coupon code'
placeholderTextColor='#0a5796'
color='#0a5796'
inputStyle={{
color: '#0a5796',
}}
inputContainerStyle={{
borderBottomWidth: 0,
height: 50,
}}
containerStyle={styles.couponInputContainer}
onChangeText={(value) =>
this.setState({ couponCode: value })
}
value={this.state.couponCode}
/>
{couponLoading ? (
<View style={styles.couponButton}>
<ActivityIndicator />
</View>
) : (
<TouchableOpacity
style={styles.couponButton}
onPress={() => this.codeCheck(couponCode, line_items)}
>
<Text style={styles.buttonText}>Apply Coupon</Text>
</TouchableOpacity>
)}
</View>
</View>
)}
/>
Arrow-Funktions are "always" executed and create a new Reference in Memory. This way they will always re-rendering if component will be executed.
For performance reasons you better define your function outside and call it like this:
function renderMyItem(){ ...bimbom... yous stuff goes here! }
function renderHeader(){ ...bimbom... yous stuff goes here! }
<Flatlist
renderItem={this.renderMyItem()}
ListHeaderComponent={this.renderHeader()}
...
/>
What happens here?
Both of your functions renderMyItem and renderHeader will be executed once if your component is loaded and will be saved in memory. So every time you call one of the functions, you call a reference to the place in memory where they are saved.
In the other case, Arrow-Functions ()=>{...} are executed in current context and generate a new reference in Memory, each time they called, because .. to say it clear: you define & call a function that way.
If you are using Functional Component then don't use Arrow function () => (...) for header and footer components of FlatList but instead only return your header and footer Components as shown in the sample below.
<FlatList
...
ListHeaderComponent={(<View><Text>Header</Text></View>)}
ListFooterComponent={(<View><Text>Footer<Text></View>)}
/>
I was going through the same problem and the accepted answer didn't worked for me. As here the problem occurs because we are updating the state whenever the text changes (as defined in onChangeText) which causes re-rendering. Thus i came up with another solution;
First i created another dict object newState which has nothing to do with state or props. So on changing newState dict, it will not cause re-rendering. Then;
newState = {}
<TextInput onChangeText={text => this.newState.value = text} />
Then i changed the state(which is necessary as per your problem and as per mine) on onEndEditing ;
<TextInput onChangeText={text => this.newState.value = text} onEndEditing={this.setSearch} />
Here is setSearch
setSearch= () => {
this.setState({couponCode: this.newState.value})
delete this.newState.value;
}
I am deleting the key after the state is set because it doesnot update correctly next time.

How to combine create and edit page in react-admin

I am new for the react and react-admin, but I am now using it in our project, everything is good, but there is one thing I don't know how to make it. in our application. the create and edit page almost same, the only difference is some fields are disabled in edit view, so I want to combine create and edit, is there any document about it. I searched it but it seems not an easy way to do it, it's appreciated if can get some sample code. thank you !!!
Hi #Mads, thank you for your answer, I update the question here. what I mean is last time, i also create a separate form like what you did and I insert the component directly as below (e.g. <Form/>). it will get an error: the invalid value for prop ‘save’ on tag
I am just curious what's the difference with this way ({form('edit')})
<Edit {...props} undoable={false} style={{width: '100%'}}> <Form/> </Edit>
You can do something like this:
const form = type => (
<SimpleForm>
<TextInput source="name"/>
{type === 'create' ? <TextInput source="created_at"/> : ''}
</SimpleForm>
);
export const EditView = ({classes, ...props}) => {
return (
<Edit {...props} undoable={false} style={{width: '100%'}}>
{form('edit')}
</Edit>
);
};
export const CreateView = ({classes, ...props}) => {
return (
<Edit {...props} undoable={false} style={{width: '100%'}}>
{form('create')}
</Edit>
);
};
I had a similar struggle and this is what I ended up doing:
// This is the reusable form component
const CategoryForm = (props) => (
<SimpleForm {...props}>
<TextInput source="name" label="Nome" />
{props.type === "edit" && <p>This element only shows in edit mode</p>}
</SimpleForm>
);
// Edit View Component
export const CategoryEdit = (props) => (
<Edit {...props}>
{/* Reusable form component with type prop set to 'edit' */}
<CategoryForm type="edit" />
</Edit>
);
// Create View Component
export const CategoryCreate = (props) => (
<Create {...props}>
{/* Reusable form component with type prop set to 'create' */}
<CategoryForm type="create" />
</Create>
);

Implementing Footer Tabs in Native React using Native Base

I am creating a native react application using native base for the UI (http://nativebase.io/docs/v2.0.0/components#footerTab). I am using the footerTabs component and my code is as follows
render() {
return (
<Container>
<Header backgroundColor="#ECEFF1">
<Button transparent>
<Icon name='ios-menu' style={{color: 'black'}}/>
</Button>
<Title style={{color:'black'}}>Header</Title>
</Header>
<Content>
<Profile/>
</Content>
<Footer backgroundColor="#212121">
<FooterTab>
<Button backgroundColor="#000" >
<Icon name="ios-person" size={30} color="#900"/>
<Text>Profile</Text>
</Button>
<Button>
<Icon name="ios-search"/>
<Text>Search</Text>
</Button>
<Button>
<Icon name="ios-camera"/>
<Text>Camera</Text>
</Button>
<Button>
<Icon name="ios-apps"/>
<Text>Apps</Text>
</Button>
<Button>
<Icon active name="ios-navigate"/>
<Text>Navigate</Text>
</Button>
</FooterTab>
</Footer>
</Container>
);
}
I have created different JS files for different functionalities such as Profiles,Search,Apps ect.. and have imported them as follows.
import Profile from './Profile';
How do I implement the onPress functionality on the buttons of the footer to change the component in the content tag depending on what was selected?
<Content>
<Profile/>
</Content>
For eg: If I pressed the search button I want the profile tag to be replaced with and similarly the same for the other buttons.
Here FooterTab from native base is not persist actual tab functionality like UITabBar in iOS, its only persist for design. What you need to do is, keep footer tag in all of your component with all four buttons and keep active accordingly. For changing view by selecting any button you need to replace current view by selected one using navigator like:
<Button onPress={()=> { this.props.navigator.replace({id:'component name'}) }}>
and in your navigator component you should define all required components in renderScene method on the basis of id value in route payload. If you want actual functionality as TabBar work then you can use this third party module react-native-tab-navigator. Thanks!
Instead of replacing the content, why don't you have each Button navigate to a new page?
Let's say you're on the Profile tab. You could do something like this:
import FooterWrapper from './FooterWrapper'
<Footer>
<FooterWrapper tab='profile' navigator={this.props.navigator} />
</Footer>
And then in your FooterWrapper (I just handled a case of two tabs):
constructor(props) {
super(props)
this.state = {
profileTab: this.props.tab === 'profile',
searchTab: this.props.tab === 'search',
}
}
navToProfilePage() {
this.props.navigator.push({
id: 'profile',
tab: 'profile',
})
}
navToSearchPage() {
this.props.navigator.push({
id: 'search',
tab: 'search',
})
}
render() {
return (
<FooterTab>
<Button active={this.state.profileTab} onPress={() => this.navToProfilePage()}>
Profile
<Icon name='ios-person' size={30} color='#900' />
</Button>
<Button active={this.state.searchTab} onPress={() => this.navToSearchPage()}>
Search
<Icon name='ios-search' />
</Button>
</FooterTab>
)
}
Ok so here is I how got it I used the renderContent method within the content tags to generate views depending on the state change when the button was clicked.
<Content>
{this._renderContent(this.state.selectedTab)}
</Content>
The selectedTab is a state variable whose state is set using this.setState in the onPress method. The renderContent has an if function that checks the selected tab and returns the appropriate view. I also tried the navigation approach but this seemed cleaner.
_renderContent = (Tab: string,) => {
if(this.state.selectedTab==="Profile"){
return (
<Profile/>
);
}
else if(this.state.selectedTab==="Search"){
}
}