включили кнопку перехода к следующему шагу, попытались установить состояние и создали новый метод onclick в переключателе - PullRequest
0 голосов
/ 17 января 2019

обновление 2:

привет

  • извините, я забыл упомянуть о вызове API в моем вопросе ранее
  • Я делаю вызов API в избыточном виде.
  • поэтому в моем файле actions / index.js я вызываю API в методе getSports.
  • но проблема в том, что когда я пытаюсь получить значения, я получаю сообщение об ошибке. 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

действия / 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>
  • Я новичок в редукционной форме.
  • Я пытаюсь включить кнопку после щелчка переключателя.
  • , чтобы включить кнопку перехода к следующему шагу. Я попытался настроить состояние и создал новый метод onclick в переключателе.
  • но все равно выдает ошибку,
  • не уверен, как передать значения переключателя для включения кнопки.
  • Можете ли вы сказать мне, как это исправить, чтобы в будущем я исправил это сам.
  • Предоставление моей песочницы и соответствующего фрагмента кода ниже.

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>

Ответы [ 3 ]

0 голосов
/ 24 января 2019

Первое, что вам нужно сделать, это удалить ссылку на this из вашего функционального компонента ...

onClick={this.passRadioValue("right")}

К

onClick={passRadioValue("right")}

Функциональные компоненты наследуют свой функциональный контекст от области действия родительской функции и не имеют объекта this. это удалит немедленные ошибки

Вот разветвленная версия или ваш кодовый блок, который я начал для справки ...

https://codesandbox.io/s/4jpkk394x7?moduleview=1

И некоторые сведения о функциональных (не сохраняющих состояние) компонентах класса (с состоянием) ...

https://programmingwithmosh.com/react/react-functional-components/

0 голосов
/ 28 января 2019

https://codesandbox.io/s/6zrw7r66rr

Я разбудил ваши коды и окно и отредактировал 4 файла. Уверен, он удовлетворяет всем вашим требованиям, указанным выше

VerticalLinearStepper.js: здесь мы храним наше состояние username, password, disabledNext (radioButton) и метод handleChange для setState. Затем мы передали состояние до -> 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 для отслеживания значения и вызываем метод setState и this.props.handleChange для setState в VerticalLinearStepper.js

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, здесь мы просто передаем реквизиты 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&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);

Дополнительная ссылка: Реакция: Компонент класса против функционального компонента

0 голосов
/ 17 января 2019

Это простой код для включения кнопки при нажатии кнопки-переключателя. Если вы хотите более информативный код, уточните свой вопрос

<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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...