I have a MUi autocomplete component inside a top bar, so it is a fixed general bar shown on all pages. My question is, how can I show the results on a different pages?
`<Autocomplete
fullWidth
id="free-solo-demo"
freeSolo
options={interests.map((option) => option.name)}
renderInput={(params) => <TextField {...params} placeholder="Search" />}
renderOption={renderOption}
/>`
Should I pass the props as paramenters?
If you want to show the autocomplete results on a different page, you will need to pass the state and options as props to the component on that page.
One way to do this is to store the state of the Autocomplete component in a higher-level component, such as the parent component that is responsible for rendering the pages. You can pass the state and options down to the Autocomplete component as props. Then, when the user navigates to a different page, you can pass the same state and options to the Autocomplete component on that page.
Here is an example:
// Parent component
function App() {
const [interests, setInterests] = useState([]);
const [selectedInterest, setSelectedInterest] = useState("");
// fetch interests data and set state
return (
<div>
<TopBar interests={interests} selectedInterest={selectedInterest} onInterestChange={setSelectedInterest} />
// Render other pages and pass interests and selectedInterest as props as needed
</div>
);
}
// TopBar component
function TopBar({ interests, selectedInterest, onInterestChange }) {
return (
<AppBar>
<Autocomplete
fullWidth
id="free-solo-demo"
freeSolo
options={interests.map((option) => option.name)}
value={selectedInterest}
onInputChange={(event, newInputValue) => {
onInterestChange(newInputValue);
}}
renderInput={(params) => <TextField {...params} placeholder="Search" />}
renderOption={renderOption}
/>
</AppBar>
);
}
Related
I'm using Material UI Autocomplete to get searched data, it works fine, but it's re-render after the search runs and clears the value without focus, then we have to click again to get fetched value.
here Is my auto-complete component
<AutoCompleteNewDesign
disableClearable
freeSolo
id="combo-box-demo"
onChange={(e, selectValue) => {
setInvoiceSelectedData(selectValue);
}}
options={invoiceSearchList}
getOptionLabel={option => (option ? String(option?.data1) : '')}
renderOption={option => (
<div>
{option.data1} - {option.data2}
</div>
)}
renderInput={params => (
<TextField
params={params}
name="name-here"
variant="outlined"
onChange={e => {
dispatch(
searchName(e.target.value);
}}
/>
)}
filterOptions={filterOptions}
/>
I used this reducer to store data which fecth when user searched
const { searchedNames } = useSelector(state => state.searchReducer);
How to call my dispatch asynchronous as well as prevent this re-render
I'm trying to build a reusable Confirmation component that renders a button and when clicked, it should open a Material UI Dialog. The button component gets passed in as a prop for the Confirmation component
<Confirmation component={() => <MUIButton>Click me</MUIButton>} />
The parent component looks like this
const Confirmation = ({ component: Component }) => {
const handleClick = () => {
...logic to open the dialog...
}
return (
<>
<Component onClick={handleClick} <-- how to trigger this? />
<Dialog />
</>
)
}
Now how would I get this to work without having to specify the onClick in the passed button component itself? For this situation one can assume the component passed as a prop is always some kind of a button.
<Confirmation
component={() => (
<MUIButton
onClick={...logic} <-- don't want to have to specify this
>
Click me
</MUIButton>
)
/>
OR am I approaching this from a wrong perspective? Should this be solved by passing the button as a child instead? As in
<Confirmation>
<MUIButton> Click me </MUIButton>
</Confirmation>
and how would the implementation be in this situation?
Thank you in advance!
Ended up solving this by creating a higher order component as suggested by John
const withConfirmation = (WrappedComponent) => {
return (props) => {
return (
<>
<WrappedComponent
// Overrides the possible onClick logic passed as a prop
onClick={ ...dialog opening logic }
{...props}
/>
<Dialog>
...
</Dialog>
</>
);
};
};
const Confirmation = withConfirmation(MuiButton)
<Confirmation>Clicking me opens a dialog</Confirmation>
What I am trying to achieve is focusing on TextInput present in child component when clicked on an icon present in parent file. I have tried using refs and forward refs but that means i have to wrap the component in forwardref which i am trying to avoid.
const InputText = React.forwardRef((props, ref) => (
<input ref={ref} {...props} />
));
My child file looks like this:
export const TextField = ({
label,
placeholder = "",
id = "",
isSecure = false,
disabled = false,
handleBlur,
handleChange,
value,
...props
}: IProps): React.ReactElement => {
const { labelStyle, fieldStyle, status=false, search=false,inputStyle, errorStyle } =
props;
//some statements
<View style={styles.elementsContainer}>
<TextInput //I want to focus on this
.......
.
.
onChangeText={handleChange(props.name)}
onBlur={handleBlur(props.name)}
/>
</View>
);
};
export default TextField;
Below is my parent file where I have an icon and on click of it I trying this textfield to be focused.
return (
<Formik
initialValues={initialValues}
onSubmit={(values, { setSubmitting }) => {
setSubmitting(false);
}}
>
{(formikProps: FormikProps<{ searchText: string }>) => (
<View style={status?styles.highlight:[styles.container,textFieldDimensions]}>
<TouchableOpacity onPress={addressFocus}> //This is the icon on click of it i am trying textfield child component to be focused.
<Icon testID="home" name={IconNames.home} />
</TouchableOpacity>
<View style={styles.textfieldContainer}>
<TextField //CHild component
handleChange={formikProps.handleChange}
status={status}
handleBlur={() => searchFunction(formikProps.values.searchText)}
value={formikProps.values.searchText}
name="searchText"
placeholder={placeholder}
search={search}
label="Search :"
id="searchText"
fieldStyle={[styles.field,fieldStyle]}
inputStyle={styles.input}
labelStyle={[styles.label, labelStyle]}
/>
</View>
</View>
)}
</Formik>
);
So after brainstorming i come to a simple approach which works for me as of now. But i am not crystal clear from ref part how its working.
so what i did is in parent file where i am passing props in child component like this:
const toggle=()=>{
setToggler(!toggler) This function changes state value which is boolean type from false to true and vice versa.
}
<TouchableOpacity onPress={toggle}> //toggle function called on onPress
<Icon testID="home" name={IconNames.home} />
</TouchableOpacity>
<TextField
toggler={toggler} //Now I am passing state toggler into child component, change of this state will re render the component
handleChange={formikProps.handleChange}
status={status}
handleBlur={() => searchFunction(formikProps.values.searchText)}
value={formikProps.values.searchText}
name="searchText"
placeholder={placeholder}
search={search}
label="Search :"
id="searchText"
fieldStyle={[styles.field,fieldStyle]}
inputStyle={styles.input}
labelStyle={[styles.label, labelStyle]}
/>
Now how i am handling refs in child component is that it focus on textinput on click of button.
All this is happening in functional component, for simplicity react rules has not been taken into account only relevant pieces of code is shown
const inputRef = useRef<TextInput>(null);
const onClickFocus = () => {
{props.toggler && inputRef.current?.focus();} //If toggler changes to true then this function will execute and perform inputRef.current?.focus();
}
onClickFocus() //Function is called here and later inputRef is utilized in textinput as ref={inputRef}
<TextInput
ref={inputRef}
placeholder={placeholder}
secureTextEntry={isSecure}
style={search? fieldStyle:[styles.inputBox, inputStyle]}
editable={!disabled}
value={value}
{...field}
onChangeText={handleChange(props.name)}
onBlur={handleBlur(props.name)}
/>
I have a component (it's called CothesCategoriesList) that receives some props (the values of those props are taken from a piece of state) and that gets rendered by a Stack navigator.
I have a form that when submitted changes the state, and theoretically should change the props that are passed to the component, but this does not happen. State changes, as i have tested, but the props don't. How can i fix this? How can i make the component receive the new props?
This is code from the component that contains the Stack navigator and that renders ClosetCategoriesList:
<ClosetStack.Screen
name="Categories"
options={({ navigation }) => ({
headerRight: props => (
<Button
onPress={() => navigation.navigate("Modal")}
color="tomato"
type="clear"
icon={<Icon name="add" size={30} color="tomato" />}
/>
)
})}
>
{props => (
<ClosetCategoriesList
{...props}
categories={categories_state.categories}
navigation={props.navigation}
/>
)}
</ClosetStack.Screen>
In the parent component i have some state created with the useState hook, which i change with the following handler:
const handleCategoryFormSubmit = category => {
let new_categories_state = [...categories_state.categories];
new_categories_state.push({
title: category.category_name,
subcategories: []
});
set_categories_state({ categories: new_categories_state });
};
Then in the component that renders each individual element i have the following code that receives as props the state from the parent component (categories):
let parsed = categories.map((category, index) => (
<ListItem
key={index}
title={category.title}
bottomDivider
onPress={() =>
navigation.push("Subcategories", {
subcategory_index: index
})
}
/>
));
return <View>{parsed}</View>;
The modal form has the following code, and i suspect that because i use navigation to go back to the Categories component, the state does not persist, and the component is rendered with the hard-coded state.
<Formik
initialValues={{ category_name: "" }}
onSubmit={(values, actions) => {
handleCategoryFormSubmit(values);
actions.resetForm();
navigation.navigate("Categories");
}}
>
It could be for so many different reasons since we don't know how you handle your state change in the parent component
1)If you are not using setState to update your state, react will not re-render the component. Avoid changing the state without using setState
2)Update child to have attribute 'key' equal to name. The component will re-render every time the key changes e.g
render() {
return <div key={this.props.bar}>{this.props.bar}</div>
}
3)Use componentDidUpdate to check if your props change and you can update your state.
Im using a flat list on 2 different screens.
On the EventListScreen:
this is the main screen and should display all events.
and on the 2nd page UserProfile.js this page should only display that users events.
in both flat lists I'm using a pure component stored in a seperate class, to where the flat lists are i.e
My Question is, I want to display an "Edit" button on the Event.js child component only if the User is on the
UserProfileScreen.js
I have looked up a lot of example but cant really find any that show how to do it
with a child pure component like I'm doing.
Any Help would be greatly appreciated! Thank you
EventListScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
{...item}
/>}
/>
Event.js
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
}
You don't need additional properties.
We can assume that the "Edit" button should be available when openEditEvent prop is defined.
Condition in event (using convertion to bool, false for undefined):
<CardSection>
<Text>{this.props.eventName}</Text>
{!!this.props.openEditEvent &&
<Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>
}
</CardSection>
Use propTypes to define openEditEvent prop as a function, optional (not required).
If I understand your problem correctly an option to solve this problem would be to pass a boolean "showable prop" to show the edit button only when required:
EventListScreen.js (Stays the same, we don't show the edit button here)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
{...item}
/>}
/>
UserProfileScreen.js (we add the shouldShowEditButton prop to event in order to show the button)
<FlatList
data={this.state.events}
// Get the item data by referencing as a new function to it
renderItem={({item}) =>
<Event
openEventDetail={() => this.openEventDetail(item)}
openEditEvent={() => this.openEditEvent(item)}
shouldShowEditButton
{...item}
/>}
/>
Event.js (We add some propTypes and defaultProps to handle the new prop, it won't show the edit button if not specified)
export default class Event extends Component {
render() {
return (
<Card>
<CardSection>
<Text>{this.props.eventName}</Text>
//I want this button to be displayed only if user is viewing
//from the UserProfile.js
{this.props.shouldShowEditButton && <Button onPress={() =>this.props.openEditEvent()}>
{this.props.displayButton}
</Button>}
</CardSection>
<TouchableOpacity
onPress={() => this.props.openEventDetail()}
>
...
...
);
...
}
}
// We add some default propTypes and definitions
Event.propTypes = {
shouldShowEditButton: PropTypes.bool
};
Event.defaultProps = {
shouldShowEditButton: false
};
In this way you're only showing the edit button for the components that have the prop shouldShowEditButton defined, and because its default value is defined as false, the components that don't have the property will behave in the same way they were before.