In my render I have:
render(){
return (
//.....
<this.Content>
//...
in Content I have all the parts that I show to user and at the end I have:
Content = props => {
return(
//..
<Submit
onSubmit={self.props.handleSubmit(values => self._onSubmit(values))}
/>
)}
Now my problem is when the submit button has clicked I would to change it with:
<Spinner animation="border" variant="primary" />
How can I do?
EDIT.
constructor(props){
super(props);
this.state = {
wasButtonClicked: false,
}
Content = props => {
return(
//
{this.state.wasButtonClicked == true ? <Spinner animation="border" variant="primary" /> : <Submit onSubmit={self.props.handleSubmit(values => {this.setState({wasButtonClicked: true}),self._onSubmit(values)})} />}
/>
}
render() {
return(
//
this.state.HasEmail === true
?
<this.Content />
:
If your using JSX you can:
Create a state wasButtonClicked and initiate it with false.
onclick of the button setState wasButtonClicked to true
Insted of rendering the button call {this.renderItem()}
Create the function:
renderItem = () => {
return this.state.wasButtonClicked ? <Spinner animation="border" variant="primary" /> : <YourBUttonELement/>
}
Steps to implement with your code in a simple language
You have added wasButtonClicked in this.state.
Use ternary condition in the return of your Content function. If wasButtonClicked is true then return <Spinner animation="border" variant="primary" />, on false return Submit button.
OnClick of your submit button setState wasButtonClicked to true.
setState wasButtonClicked to false whenever your required operation completed.
Style the Spinner wrap it inside a div or way suitable to look similar to the button
EDITED
Use this instead of your Content function
Content = props => {
return (
this.state.wasButtonClicked
? <Spinner animation="border" variant="primary" />
: <Submit onSubmit={() => self.props.handleSubmit(values => {
this.setState({ wasButtonClicked: true });
self._onSubmit(values);
})} />
)
}
I don't know what is self referred to in your code is it the this keyword you are using here. I made your code syntactically correct.
Related
I have the following code which I'm trying to refactor
const [edit, setEdit] = useState(false);
<ListItemText
primary={edit ?
<TextareaAutosize ... />
: <Typography ..../>}
/>
The TextareaAutosize repeats a lot through the app so I thought I would convert it into a separate component.
export default function Textarea(props) {
const [edit, setEdit] = useState(false);
if(edit){
return(
<TextareaAutosize .../>
)
}
return false
}
As you can see, if edit is false the component returns false. The back at the top I thought I would do this
import Textarea from "../Textarea";
<ListItemText
primary={Textarea ?
<Textarea ... />
: <Typography ..../>}
/>
By my logic, there should be a way to check if component Textarea will return false, right?
A "component" (JSX) is a UI element. You must return JSX or null, and the rendering engine will render the returned JSX or nothing if null.
You can check a flag and short-circuit:
{isFlag && <MyComponent ... />}
or have the component render or not (or if you want to keep state just show/hide):
<MyComponent isVisible={isFlag} />
Or possible return different components depending on flags:
if (isLoading) {
return <MyLoadingSkeletonComponent />
}
<MyMainUIComponent />
EDIT:
You may want to refactor into a compound component where you take the flag and hide the show/hide logic within it
const TextArea = ({edit, editMode, viewMode}) => (
edit ? editMode : viewMode
)
// Call it with the flag and both components:
<TextArea
edit={edit}
editMode={<TextareaAutosize ... />}
viewMode={<Typography ... />}
/>
Have the best of the two worlds, your idea of refactoring is correct, but it is missing something.
try something like this:
export default function Textarea(props) {
props.edit ? <TextareaAutosize .../> : <Typography ..../>
}
and
<ListItemText
primary=<TextareaAutosize {edit} ... />
/>
In this case you have one place to change TextareaAutosize and Typography codes, less messy code in parent listing.
Hope this helps.
I am working in an application where in a page it have a button. When I select the button it will go to another page.
I am using Push in UseHistory() to pass between pages. I know we can go to a specific div using anchor tag. But I don't want to use anchor tag. Can anyone help me how can I do that in react.
This is the button component I used to redirect to another page.
const { push } = useHistory();
return (
<>
{surveyDisableTime && <SurveyInfoBox />}
<EmptyList
image={<NoDataIcon />}
title={formatMessage({ id: 'event.survey_response.assign_survey.heading' })}
subtitle={formatMessage({ id: 'event.survey_response.assign_survey.subheading' })}
onButtonClick={() => push(AppRoute.editEvent.replace(':eventId', event.id), { from: pathname })}
buttonText={formatMessage({ id: 'event.survey_response.assign_survey.button_label' })}
disabled={surveyDisableTime}
/>
</>
);
This is the onclick function -> onButtonClick={() => push(AppRoute.editEvent.replace(':eventId', event.id), { from: pathname })}
In the editEvent I need to go to a specific component. How can I do that?
Lets say this is the component of the page the router will reload to,
return (
<div className={classes.container}>
<div className={classes.creatEventContainer}>
<div className={classes.formWrapper}>
<BasicInfoSection
institutionOptions={institutionOptions}
seasons={seasons || []}
isSeasonFieldDisabled={isSeasonFieldDisabled}
{...props}
/>
<EventLocation isVisible={!!isInPerson} errors={errors} register={register} {...props} />
<SurveySelection
isSurveyFieldDisabled={isSurveyFieldDisabled}
isVisible={!!isSurvey}
{...props}
/>
<DateAndTimeSection control={control} errors={errors} />
<NameRecordingsServicesSectionContainer
fields={fields}
remove={remove}
append={append}
languageVoices={languageVoices}
/>
</div>
</div>
</div>
)
I need to go to component.
Thankyou in advance.
try useNavigate() instead because the hook useHistory is not supported in react-router-dom v6 anymore!
if filledOutTheSurvey is false then return Survey component
but if the user fills out then the state of filledOutSurvey would be true and AnotherComponent would render
...
const [filledOutTheSurvey, setFilledOutTheSurvey] = useState(false);
return (
<div>
{filledOutTheSurvey === true ? <AnotherComp/> : filledOutTheSurvey === false ? <Survey setFilledOutTheSurvey={setFilledOutTheSurvey} /> : null }
</div>
)
...
function Survey({setFilledOutTheSurvey}){
return <form onSubmit={() => setFilledOutTheSurvey(true)}>...</form>
}
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>
I am trying to pass my function updateProfile as a prop in the Button component shown below. The function is not working and the application crashes when I press the button.
Here is the code of button component.
const Button = (props) => {
return (
<>
<TouchableOpacity
style={styles.buttonContainer}
disabled={props.disabled}
onPress={props.functionCall}
>
<Text style={styles.buttonText}>{props.title}</Text>
</TouchableOpacity>
</>
);
};
And here is how I am using
<Button disabled={isLoading ? true : false} functionCall="updateProfile" title="Edit Profile"/>
The function
const updateProfile = () => {
navigation.navigate("updateProfile", member);
};
Actually, I have many buttons and each button has different function call. So, it needs to be sented through props. Help needed!
Change this:
functionCall="updateProfile"
to this:
functionCall={updateProfile}
I am unable to see my component for the "Log Out" aspect.
It is not entirely invisible, but instead of a block style just a single line is visible with no text.
However, The same reusable Button component works with the "Log In button".
renderContent() {
switch (this.state.loggedIn) {
case true:
return <Button> Log Out </Button>;
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
render() {
return (
<View>
<Header headerText="Authentication" />
{this.renderContent()}
</View>
);
when the user is not logged in the output is as follows:
the dark blue line below the Authentication header is the
However, The same Button with "Log In" works well.
I have tried to render a text component in place of the button component and it also works. Seems like just the Button in this particular conditional rendering is not working!
My Button component:
const Button = ({ onPress, children }) => {
const { buttonStyle, buttonTextStyle } = styles;
console.log({ children });
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={buttonTextStyle}>
{children}
</Text>
</TouchableOpacity>
);
};
the code block where Log In works:
renderButton() {
if (this.state.loading) {
return <Spinner size="small" />
}
return (
<Button onPress={this.onButtonPress.bind(this)}>
Log In
</Button>
);
}