启用转到下一步按钮,尝试设置状态并在单选按钮中创建新的 onclick 方法
Posted
技术标签:
【中文标题】启用转到下一步按钮,尝试设置状态并在单选按钮中创建新的 onclick 方法【英文标题】:enable the go to next step button, tried setting up state and created new onclick method in the radio button 【发布时间】:2019-06-11 21:01:23 【问题描述】:更新 2:
你好,
抱歉,我之前的问题中忘记提及 api 调用了 我以 redux 方式进行 api 调用。 所以在我的 actions/index.js 文件中,我在 getSports 方法中调用我的 api。 但问题是当我尝试检索值时出现错误。A cross-origin error was thrown. React doesn't have access to the actual error object in development. See b.me/react-crossorigin-error for more information.
所以我调试了类 AsyncValidationForm console.log("AsyncValidationForm this.props---->", this.props);
中的道具
那里我没有看到 getSports 方法。
您能告诉我如何检索这些值,以便我可以将它们分配给我的单选按钮标签。
https://codesandbox.io/s/yv1zpj874x
actions/index.js
import axios from "axios";
export function testData()
let response = data: "test" ;
return
;
export function getSports()
return dispatch =>
axios
.get("https://jsonplaceholder.typicode.com/users") //works
.then(response =>
)
.catch(error =>
);
;
AsyncValidationForm.js
import * as actions from "../actions";
class AsyncValidationForm extends React.Component
constructor(props)
super(props);
console.log("AsyncValidationForm this.props---->", this.props);
this.state =
//pass down VerticalLinearStepper.js state if any
username: this.props.username ? this.props.username : "",
password: this.props.password ? this.props.password : "",
//this determines whether any fields is filled or not from VerticalLinearStepper
pristine:
this.props.username || this.props.password || !this.props.disabledNext
? false
: true
;
AsyncValidationForm.js 中的单选按钮标签
<label>
<Field
name="sex"
component=renderField
type="radio"
value="male"
checked=!this.props.disabledNext
onChange=this.passRadioValue
/>" "
Male
</label>
我是 redux 表单的新手。
我尝试在单击单选按钮后启用该按钮。
为了启用转到下一步按钮,我尝试设置状态并在单选按钮中创建新的 onclick 方法。
但仍然抛出错误,
不确定如何传递单选按钮值来启用按钮。
能否告诉我如何修复它,以便我以后自己修复它。
下面提供我的沙盒和相关代码sn-p。
update1:现在只删除了这个错误 https://codesandbox.io/s/4jpkk394x7?moduleview=1
https://codesandbox.io/s/pjj6m1l9pq
AsyncValidationForm.js
const AsyncValidationForm = props =>
console.log("AsyncValidationForm ---->");
const handleSubmit, pristine, reset, submitting = props;
// this.state =
// disabled: false
// ;
// this.setState( disabled: !this.state.disabled );
const passRadioValue = (e) =>
return (
<form onSubmit=handleSubmit>
<Field
name="username"
type="text"
component=renderField
label="Username"
/>
<Field
name="password"
type="password"
component=renderField
label="Password"
/>
<label>
<Field name="sex"
component=renderField type="radio" value="male"
onClick=this.passRadioValue("right") />" "
Male
</label>
<div>
<button type="submit" disabled=submitting>
Sign Up
</button>
<button type="button" disabled=pristine || submitting onClick=reset>
Clear Values
</button>
</div>
</form>
);
;
StepTemplate.js
<Button
variant="contained"
color="primary"
onClick=onNext
className=classes.button
>
canGoBack ? "Next" : "go to next step"
</Button>
【问题讨论】:
您的沙箱应该是minimal 示例。如果上面的 sn-ps 是相关代码,那么您的沙箱中应该几乎没有其他任何内容。 @RyanCogswell 嘿,我删除了不必要的文件,你现在能帮我吗 沙盒在我看来没有什么不同。 嘿,我正在使用步进器并减少形式,所以这些代码应该在那里....不知道如何通过删除这些代码来重现....你能告诉我 @RyanCogswell 我在我的沙盒中尝试过,它不起作用...你能在我的沙盒中更新吗 【参考方案1】:这是一个在单选按钮单击时启用按钮的简单代码 如果您想要一个更具描述性的问题,请详细说明您的问题
<html>
<script>
function enableButton()
document.getElementById("button").disabled = true;
</script>
<input type="radio" name="gender" value="male" onclick="JaaScript:enableButton()"> Male<br>
<button type="button" id="button">Click Me!</button>
</html>
【讨论】:
嘿,在 AsyncValidationForm.js 中,我添加了单选按钮,您可以在其中添加点击事件吗....这样可以帮助我进一步进行操作....您可以直接在我的沙箱中更新吗 我在我的沙盒中尝试过,它不起作用...你能在我的沙盒中更新吗【参考方案2】:您需要做的第一件事是从您的功能组件中删除对this
的引用...
onClick=this.passRadioValue("right")
到
onClick=passRadioValue("right")
函数组件从父函数的作用域继承它们的函数上下文并且没有this
对象。这将消除即时错误
这是一个分叉版本或您的代码笔,我已经开始参考...
https://codesandbox.io/s/4jpkk394x7?moduleview=1
还有一些关于功能(无状态)与类(有状态)组件的背景......
https://programmingwithmosh.com/react/react-functional-components/
【讨论】:
嘿,但是只有在我选择单选按钮中的选项后才能启用转到下一步按钮,你能帮我吗 是的,这是我的下一个问题。不过我明天得帮你。抱歉,晚上注销 好的,谢谢...当您更新时,您可以使用 cmets 进行更新 你忙吗?你能帮忙吗 我必须在今晚晚些时候再讨论这个问题,但到时候肯定会尝试一下。【参考方案3】:https://codesandbox.io/s/6zrw7r66rr
我已经分叉了你的代码框,并编辑了 4 个文件。很确定它满足您上述所有要求
VerticalLinearStepper.js:这是我们为setState
存储username, password, disabledNext (radioButton)
状态和handleChange
方法的地方。然后,我们将状态传递给 -> Step1.js
-> AsyncValidationForm.js
。
class VerticalLinearStepper extends React.Component
state =
activeStep: 0,
//we set our state in this parent
disabledNext: true,
username: "",
password: ""
;
steps =
"Select campaign settings": Step1,
"Create an ad group": Step2,
"Create an ad": Step3
;
//setState for disabledNext
handleChangeDisabledNext = value =>
this.setState( disabledNext: value );
;
//setState for username, password
handleChange = (name, value) =>
this.setState( [name]: value );
;
stepsCount = () => Object.values(this.steps).length;
canGoBack = () => this.state.activeStep > 0;
canGoForward = () => this.state.activeStep < this.stepsCount();
isFinished = () => this.state.activeStep === this.stepsCount();
handleBack = () =>
if (this.canGoBack())
this.setState(prevState => ( activeStep: prevState.activeStep - 1 ));
;
handleNext = () =>
if (this.canGoForward())
this.setState(prevState => ( activeStep: prevState.activeStep + 1 ));
;
handleReset = () => this.setState( activeStep: 0 );
render()
const classes = this.props;
const activeStep = this.state;
return (
<div className=classes.root>
<Stepper activeStep=activeStep orientation="vertical">
Object.entries(this.steps).map(([label, CustomStep]) => (
<Step key=label>
<StepLabel>label</StepLabel>
<StepContent>
<CustomStep
canGoBack=this.canGoBack()
canGoForward=this.canGoForward()
onBack=this.handleBack
onNext=this.handleNext
classes=classes
//we pass down the state and its' setState method
handleChangeDisabledNext=this.handleChangeDisabledNext
disabledNext=this.state.disabledNext
handleChange=this.handleChange
username=this.state.username
password=this.state.password
/>
</StepContent>
</Step>
))
</Stepper>
this.isFinished() && (
<Paper square elevation=0 className=classes.resetContainer>
<Typography>All steps completed - you're finished</Typography>
<Button onClick=this.handleReset className=classes.button>
Reset
</Button>
</Paper>
)
</div>
);
在AsyncValidationForm.js
中,我们绑定onChange
方法来跟踪值,并在VerticalLinearStepper.js
中调用setState
方法和this.props.handleChange
为setState
const renderField = (
input,
label,
type,
//checked is for radio, initialValue is for setting the username, password value
checked,
initialValue,
meta: asyncValidating, touched, error
) =>
return (
<div>
<label>label</label>
<div className=asyncValidating ? "async-validating" : "">
<input
...input
value=initialValue //add value attr
checked=checked //add checked attr
type=type
placeholder=label
/>
touched && error && <span>error</span>
</div>
</div>
);
;
class AsyncValidationForm extends React.Component
constructor(props)
super(props);
console.log("AsyncValidationForm ---->");
this.state =
//pass down VerticalLinearStepper.js state if any
username: this.props.username ? this.props.username : "",
password: this.props.password ? this.props.password : "",
//this determines whether any fields is filled or not from VerticalLinearStepper
pristine:
this.props.username || this.props.password || !this.props.disabledNext
? false
: true
;
passRadioValue = e =>
this.setState( pristine: false , () =>
this.props.handleChangeDisabledNext(!e.target.checked);
);
;
handleChange = name => event =>
const value = event.target.value;
this.setState(
[name]: value,
pristine: false
,
() =>
this.props.handleChange(name, value); //setState username, password of VerticalLinearStepper.js
);
;
resetForm = () =>
this.props.handleChangeDisabledNext(true); //setState disabledNext of VerticalLinearStepper.js
this.setState(
username: "",
password: "",
pristine: true
,
() =>
this.props.handleChange("username", "");
this.props.handleChange("password", "");
);
this.props.reset();
;
// this.setState( disabled: !this.state.disabled );
render()
const handleSubmit, pristine, reset, submitting = this.props;
return (
<form onSubmit=handleSubmit>
<Field
name="username"
type="text"
component=renderField
label="Username"
initialValue=this.state.username
onChange=this.handleChange("username")
/>
<Field
name="password"
type="password"
component=renderField
label="Password"
initialValue=this.state.password
onChange=this.handleChange("password")
/>
<label>
<Field
name="sex"
component=renderField
type="radio"
value="male"
checked=!this.props.disabledNext
onChange=this.passRadioValue
/>" "
Male
</label>
<div>
<button type="submit" disabled=submitting>
Sign Up
</button>
<button
type="button"
disabled=(pristine || submitting) && this.state.pristine //add state.pristine checking
onClick=this.resetForm
>
Clear Values
</button>
</div>
</form>
);
然后,在StepTemplate.js
添加disabledNext, checkDisabledNext
道具。 checkDisabledNext
确定下一个按钮是否有条件检查。 disabledNext
是禁用值。
const StepTemplate = (
classes,
canGoBack,
canGoForward,
onBack,
onNext,
text,
children,
//we pass down these 2 values
disabledNext,
checkDisabledNext
) => (
<Fragment>
<Typography>text</Typography>
<div className=classes.actionsContainer>
<div>
children
<Button
disabled=!canGoBack
onClick=onBack
className=classes.button
>
Back
</Button>
<Button
variant="contained"
color="primary"
onClick=onNext
className=classes.button
//determine whether we should check button disabled or not
disabled=checkDisabledNext ? disabledNext : false
>
canGoBack ? "Next" : "go to next step"
</Button>
</div>
</div>
</Fragment>
);
这是Step1.js
,这里我们只是将props传递给StepTemplate
和AsyncValidationForm
:
const Step = props => (
<StepTemplate
text=`
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
`
//we want to apply checking on Step1.js, so we add checkDisabledNext attribute
checkDisabledNext=true
// disabledNext=this.props.disabledNext //no need to do this because will be passed with ...props below
...props
>
<form>
form for the first step here
<div>test here</div>
<AsyncValidationForm
onSubmit=values =>
console.log(values);
alert(
`Values: username: $values.username password: $values.password`
);
//these are the props passed down from VerticalLinearStepper.js
handleChangeDisabledNext=props.handleChangeDisabledNext
disabledNext=props.disabledNext
handleChange=props.handleChange
username=props.username
password=props.password
/>
</form>
</StepTemplate>
);
这里是重新渲染问题修复:
https://codesandbox.io/s/vqvxj7ky4y
更新VerticalLinearStepper.js
,那么我们就不需要Step1.js文件了,因为我们把Step1.js的内容写在了这个文件里:
import React from "react";
import PropTypes from "prop-types";
import withStyles from "@material-ui/core/styles";
import Stepper from "@material-ui/core/Stepper";
import Step from "@material-ui/core/Step";
import StepLabel from "@material-ui/core/StepLabel";
import StepContent from "@material-ui/core/StepContent";
import Button from "@material-ui/core/Button";
import Paper from "@material-ui/core/Paper";
import Typography from "@material-ui/core/Typography";
// import Step1 from "./steps/Step1";
import Step2 from "./steps/Step2";
import Step3 from "./steps/Step3";
import StepTemplate from "./steps/StepTemplate";
import AsyncValidationForm from "./forms/AsyncValidationForm";
const styles = theme => (
root:
width: "90%"
,
button:
marginTop: theme.spacing.unit,
marginRight: theme.spacing.unit
,
actionsContainer:
marginBottom: theme.spacing.unit * 2
,
resetContainer:
padding: theme.spacing.unit * 3
);
class VerticalLinearStepper extends React.Component
state =
activeStep: 0,
//we set our state in this parent
disabledNext: true,
username: "",
password: ""
;
steps =
//we pass the content of Step1 here, so we dont have to pass props
"Select campaign settings": props => (
<StepTemplate
text=`
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
For each ad campaign that you create, you can control how much you're
willing to spend on clicks and conversions, which networks and
geographical locations you want your ads to show on, and more.
`
//we want to apply checking on Step1.js, so we add checkDisabledNext attribute
checkDisabledNext=true
disabledNext=this.state.disabledNext //use this class' state
...props
>
<form>
form for the first step here
<div>test here</div>
<AsyncValidationForm
onSubmit=values =>
console.log(values);
alert(
`Values: username: $values.username password: $
values.password
`
);
//we use this class setstate , no need to pass down props
handleChangeDisabledNext=this.handleChangeDisabledNext
disabledNext=this.state.disabledNext
handleChange=this.handleChange
username=this.state.username
password=this.state.password
/>
</form>
</StepTemplate>
),
"Create an ad group": Step2,
"Create an ad": Step3
;
//setState for disabledNext
handleChangeDisabledNext = value =>
this.setState( disabledNext: value );
;
//setState for username, password
handleChange = (name, value) =>
this.setState( [name]: value );
;
stepsCount = () => Object.values(this.steps).length;
canGoBack = () => this.state.activeStep > 0;
canGoForward = () => this.state.activeStep < this.stepsCount();
isFinished = () => this.state.activeStep === this.stepsCount();
handleBack = () =>
if (this.canGoBack())
this.setState(prevState => ( activeStep: prevState.activeStep - 1 ));
;
handleNext = () =>
if (this.canGoForward())
this.setState(prevState => ( activeStep: prevState.activeStep + 1 ));
;
handleReset = () => this.setState( activeStep: 0 );
render()
const classes = this.props;
const activeStep = this.state;
return (
<div className=classes.root>
<Stepper activeStep=activeStep orientation="vertical">
Object.entries(this.steps).map(([label, CustomStep]) => (
<Step key=label>
<StepLabel>label</StepLabel>
<StepContent>
<CustomStep
canGoBack=this.canGoBack()
canGoForward=this.canGoForward()
onBack=this.handleBack
onNext=this.handleNext
classes=classes
/>
</StepContent>
</Step>
))
</Stepper>
this.isFinished() && (
<Paper square elevation=0 className=classes.resetContainer>
<Typography>All steps completed - you're finished</Typography>
<Button onClick=this.handleReset className=classes.button>
Reset
</Button>
</Paper>
)
</div>
);
VerticalLinearStepper.propTypes =
classes: PropTypes.object
;
export default withStyles(styles)(VerticalLinearStepper);
其他参考:React: Class Component vs Functional Component
【讨论】:
评论不用于扩展讨论;这个对话是moved to chat。 @Alvin 用于保留使用username: "",
的文本框值,但如何保留单选按钮值
@nos-s-r 我们不要再添加cmets了,我们可以用聊天了以上是关于启用转到下一步按钮,尝试设置状态并在单选按钮中创建新的 onclick 方法的主要内容,如果未能解决你的问题,请参考以下文章