启用转到下一步按钮,尝试设置状态并在单选按钮中创建新的 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&apos;re finished</Typography>
            <Button onClick=this.handleReset className=classes.button>
              Reset
            </Button>
          </Paper>
        )
      </div>
    );
  

AsyncValidationForm.js中,我们绑定onChange方法来跟踪值,并在VerticalLinearStepper.js中调用setState方法和this.props.handleChangesetState

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传递给StepTemplateAsyncValidationForm

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&apos;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 方法的主要内容,如果未能解决你的问题,请参考以下文章

按钮跳转到下一个锚点

如何在单选按钮组框中获取用户的选择以进行进一步处理?

离子标签不会转到下一页

点击按钮跳转到下一题js

如何在单选按钮单击时使按钮无效?

如何在python中使用selenium或scrapy单击“下一步”按钮