Манипулирование DOM вне рендеринга

#javascript #reactjs

#javascript #reactjs

Вопрос:

Я новичок в React и пытаюсь выполнить простой вход в систему с помощью одного API. Соединение работает нормально, поэтому я хочу создать div при сбое входа в систему.

Например, один div «Неверный пользователь или пароль» после предупреждения («НЕ ВОЙТИ»)

Я читал документацию stackoverflow и react, но у меня есть сомнения, потому что я хочу манипулировать DOM вне рендеринга.

Например, этот код:

 render() {
  var renderedOutput = arr.map(item => <div> {item} </div>)

  return (
    <div>
      {renderedOutput}
    </div>
  );
}
 

что-то вроде этого var. Возможно, это ошибка очень новичка, но я застрял. Благодарим за помощь и сожалеем о проблемах.

 import *;

class App extends Component {
  handleSubmit = e => {
    e.preventDefault();

    const user = {
      usuario: this.usuario.value,
      contraseña: this.password.value
    };

    axios.post(`http://api`, user).then(res => {
      this.setState({
        data: res.data,
        loading: true
      });

      if (Object.keys(res.data).length > 0) {
        alert("LOGIN");
      } else {
        alert("NOT LOGIN");
      }

      console.log(res.data);
    });
  }

  render() {
    return (
      <Container>
        <Form onSubmit={this.handleSubmit}>
          <Row>
            <Col md="4"> </Col>{" "}
            <Col md="4">
              <Card>
                <CardBody>
                  <FormGroup>
                    <InputGroup>
                      <InputGroupAddon addonType="append">
                        <InputGroupText>
                          <FontAwesomeIcon icon={faUser} />{" "}
                        </InputGroupText>{" "}
                      </InputGroupAddon>{" "}
                      <Input
                        placeholder="Usuario"
                        type="text"
                        innerRef={element => {
                          this.usuario = element;
                        }}
                      />{" "}
                    </InputGroup>{" "}
                  </FormGroup>
                  <FormGroup>
                    <InputGroup>
                      <InputGroupAddon addonType="append">
                        <InputGroupText>
                          <FontAwesomeIcon icon={faKey} />{" "}
                        </InputGroupText>{" "}
                      </InputGroupAddon>{" "}
                      <Input
                        placeholder="Password"
                        type="password"
                        innerRef={element => {
                          this.password = element;
                        }}
                      />{" "}
                    </InputGroup>{" "}
                  </FormGroup>
                  <Row>
                    <Col md="8"> </Col>{" "}
                    <Col md="4">
                      <Button color="success"> Login </Button>{" "}
                    </Col>{" "}
                  </Row>{" "}
                </CardBody>{" "}
              </Card>{" "}
            </Col>{" "}
            <Col md="4"> </Col>{" "}
          </Row>{" "}
        </Form>
      </Container>
    );
  }
}

export default App;
 

Комментарии:

1. Старайтесь избегать прямых манипуляций с DOM в React, если можете. Вы могли бы добавить фрагмент состояния, называемый, например error , который вы обновляете при получении ошибки, и использовать его для отображения ошибки в методе рендеринга.

Ответ №1:

Вам не нужно выполнять какие-либо ручные манипуляции с DOM для решения проблем такого типа. «Правильным» способом сделать это было бы обновление state ( setState ) после завершения вашего асинхронного запроса, что приведет к повторному рендерингу. Вы можете сохранять ошибки, если запрос завершается неудачно, и очищать их, если запрос выполнен успешно (вы также, вероятно, уйдете с этой страницы при успешном входе в систему, но это выходит за рамки).

Вот тривиальный рабочий пример, который должен продемонстрировать, как вы можете условно отображать ошибки. (Поскольку это пример, не имеет значения, что вы вводите в форму — нажмите «Отправить», чтобы сделать запрос, который будет 404 и обновить состояние с ошибкой).

 class Example extends React.Component {
  constructor (props) {
    super(props)

    this.state = {errors: []}
  }

  setErrors = (...errors) => {
    this.setState({errors})
  }

  submitForm = () => {
    // intentionally return a 404 as an example
    // change to false to mock a valid ajax request
    const hasError = true
    
    axios.get(`https://jsonplaceholder.typicode.com/${
    hasError ? 'fake' : 'todos/1'}`)
      .then(() => {
        this.setErrors()
      })
      .catch(() => {
        this.setErrors('Invalid Email Or Password')
      })
  
  }

  render () {
    return (
      <div>
        <div style={{color: 'red'}}>
          {this.state.errors.map(e => <div>{e}</div>)}
        </div>
        <div><label>Email<input type="email" /></label></div>
        <div><label>Password<input type="password" /></label></div>
        <button type="button" onClick={this.submitForm}>Submit</button>
      </div>
    )
  }
}

ReactDOM.render(<Example />, document.querySelector('#app')) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.18.0/axios.js"></script>

<div id="app"></div> 

Комментарии:

1. Действительно спасибо! Был идеальным ответом. Теперь я получаю немного лучшее представление о том, как работать с dom в react, и это делается в моем коде. Спасибо!

Ответ №2:

Вам необходимо установить информацию об ошибке в состояние при обнаружении сбоя API, затем в функции рендеринга, если обнаружено состояние ошибки, вы можете соответствующим образом отобразить html-код сообщения об ошибке. мы можем написать любой javascript в рендеринге, прежде чем возвращать jsx.

 import *;
class App extends Component {
state={
   data: null,
   loading: false,
   errorMessage: ''
}
   handleSubmit = e => {
   e.preventDefault();

   const user = {
     usuario: this.usuario.value,
     contraseña: this.password.value
   };

   axios.post(`http://api`, user).then(res => {
    this.setState({
      data: res.data,
      loading: true
    });

  if (Object.keys(res.data).length > 0) {
    alert("LOGIN");
    this.setState({
        errorMessage: ''
     });
  } else {
     this.setState({
        errorMessage: 'Bad Login details'
     });
     alert("NOT LOGIN");
  }

  console.log(res.data);
});
}

render() {
let errorMessageHtml;
if(this.state.errorMessage){
    errorMessageHtml = <p>{this.state.errorMessage}</p>
}
return (
  <Container>
    <Form onSubmit={this.handleSubmit}>
      <Row>
        <Col md="4"> </Col>{" "}
        <Col md="4">
          <Card>
            <CardBody>
              <FormGroup>
                <InputGroup>
                  <InputGroupAddon addonType="append">
                    <InputGroupText>
                      <FontAwesomeIcon icon={faUser} />{" "}
                    </InputGroupText>{" "}
                  </InputGroupAddon>{" "}
                  <Input
                    placeholder="Usuario"
                    type="text"
                    innerRef={element => {
                      this.usuario = element;
                    }}
                  />{" "}
                </InputGroup>{" "}
              </FormGroup>
              <FormGroup>
                <InputGroup>
                  <InputGroupAddon addonType="append">
                    <InputGroupText>
                      <FontAwesomeIcon icon={faKey} />{" "}
                    </InputGroupText>{" "}
                  </InputGroupAddon>{" "}
                  <Input
                    placeholder="Password"
                    type="password"
                    innerRef={element => {
                      this.password = element;
                    }}
                  />{" "}
                </InputGroup>{" "}
              </FormGroup>
              <Row>
                <Col md="8"> </Col>{" "}
                <Col md="4">
                  <Button color="success"> Login </Button>{" "}
                </Col>{" "}
              </Row>{" "}
            </CardBody>{" "}
          </Card>{" "}
        </Col>{" "}
        <Col md="4"> </Col>{" "}
      </Row>{" "}
      {errorMessageHtml}
    </Form>
  </Container>
  );
 }
}

export default App;
 

Комментарии:

1. Я получаю сообщение об ошибке: TypeError: this.state равно нулю. В if(this.state.ErrorMessage). Это что-то похожее, я не знаю почему, но не могу получить значение чего-либо вне рендеринга.

2. Я забыл добавить объект состояния в класс, прежде чем обращаться к нему, пожалуйста, проверьте обновленный код.