Как вернуть переменную из вызываемого компонента

#javascript #reactjs #react-props

Вопрос:

У меня проблема: у меня есть мой основной класс Input.js. Пользователь может выбрать фотографию и загрузить ее. Проблема в том, что я хочу проверить, загрузил ли пользователь фотографию или нет, когда он нажимает кнопку. Например, я могу привести из Profilepic.js чтобы Pic.js картинка в качестве реквизита. Но как я мог вернуть переменную? Например, я хочу установить переменную в Profilepic.js и когда пользователь нажимает кнопку, должен выполняться метод onClick (). Внутри этого метода он должен проверить, какое значение имеет переменная isPreview. И если Пользователь не загрузил фотографию, должна быть надпись, сигнализирующая ему, что он должен загрузить изображение, чтобы продолжить.

Input.js

 import React, { useState, useEffect } from 'react';
import { InputTags } from 'react-bootstrap-tagsinput';
import 'react-bootstrap-tagsinput/dist/index.css';
import './Input.css';
import Profilepic from './Profilepic';




const Input = () => {



    

  const checkAll = () => {
   
     // Call Preview from Profilepic.js
  }
  
  return (

    <div className="body-container">
            <Profilepic></Profilepic>
                <div className="row gutters">
                  <div className="col-xl-12 col-lg-12 col-md-12 col-sm-12 col-12">
                    <div className="text-right">
                      <button type="button" id="submit" name="submit" className="btn btn-primary" onClick={checkAll}>Speichern amp;amp; Weiter <i class="fas fa-paper-plane"></i></button>
                    </div>
                  </div>
                </div>
    </div>
  );
}

export default Input
 

Profilepic.js

 import React, { useState } from "react";
import { Pic } from "./Pic.js";

const Profilpic = () => {
  const [preview, setPreview] = useState(null);
  const [isPreview, setIsPreview] = useState(false);

  const fileSelectedHandler = (event) => {
    try {
      console.log(event.target.files[0]);
      if (event.target.files[0].size > 70001680) {
        alert("File is too big! Wie Samys Dick");
      } else {
        let img = URL.createObjectURL(event.target.files[0]);
        setPreview(img);
        setIsPreview(true);
      }
    }
    catch (err) {

    }
  };



  return (
    <div>
      {preview ? (
        <div>
          <label htmlFor="myInput">
            <Pic preview={preview}></Pic>
          </label>
          <input
            id="myInput"
            style={{ display: "none" }}
            type={"file"}
            onChange={fileSelectedHandler}
          />
        </div>
      ) : (
        <div>
          <label htmlFor="myInput">
            <i className="fas fa-user-circle"></i>
          </label>
          <input
            id="myInput"
            style={{ display: "none" }}
            type={"file"}
            accept=".png,.jpg,.jpeg, .jfif"
            onChange={fileSelectedHandler}
          />
        </div>
      )}
    </div>
  );
};

export default Profilpic;
 

Pic.js

 import React from "react";
import "./Photo.css";

const STYLES = ["btn--primary", "btn--outline", "btn--test"];

const SIZES = ["btn--medium", "btn--large"];

export const Pic = ({ preview }) => {
  //const checkButtonStyle = STYLES.includes(buttonStyle) ? buttonStyle : STYLES[0];
  //const checkButtonSize = SIZES.includes(buttonSize) ? buttonSize : SIZES[0];
  // Püsh for Samy
  return (
    <div class="profilepic">
      <img
        class="profilepic__image"
        src={preview}
        width="120"
        height="120"
        alt="Profibild"
      />
      <div class="profilepic__content">
        <span class="profilepic__icon">
          <i class="fas fa-camera"></i>
        </span>
        <span class="profilepic__text">Profilbild ändern</span>
      </div>
    </div>
  );
};
 

Описание проблемы

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

1. Передайте обратный вызов от родительского компонента к дочернему компоненту, чтобы ребенок мог вызвать и передать данные обратно родителю. Смотрите: Поднятие Состояния Вверх

2. @DrewReese спасибо вам за помощь! Я в замешательстве… :/ Не могли бы вы показать мне небольшой пример с крючками React в моем случае? Я сожалею об обстоятельствах.

3. Конечно. Что конкретно вы хотите передать обратно Profilepic Input и когда?

4. Я хочу перейти isPreview от дочернего компонента Profileepic.js к Input.js тому, когда метод checkAll() вызывается в Input.js .

Ответ №1:

Вы можете использовать ручку useImperativeHandle. Для этого требуется немного обернуть

Профиль

 import React, { forwardRef, useImperativeHandle, useState } from "react";
import { Pic } from "./Pic.js";

function Profilepic(props, ref) {
  const [preview, setPreview] = useState(null);
  const [isPreview, setIsPreview] = useState(false);

  useImperativeHandle(
    ref,
    () => ({ isPreview }),
    [isPreview]
  );

  ...

  return (
    ...
  );
};

export default forwardRef(Profilepic);
 

Ввод

 import React, { useState, useEffect, useRef } from 'react';
import Profilepic from './Profilepic';

const Input = () => {
  const profilePicRef = useRef();

  const checkAll = () => {
    // access profilePicRef.current.isPreview
  }
  
  return (
    <div className="body-container">
      <Profilepic ref={profilePicRef} />
      ...
        <button
          type="button"
          id="submit"
          name="submit"
          className="btn btn-primary"
          onClick={checkAll}
        >
          Speichern amp;amp; Weiter <i class="fas fa-paper-plane" />
    </button>
      ...
    </div>
  );
}
 

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

1. Большое спасибо!!! К сожалению, в этом есть ошибка TypeError: Assignment to constant variable. Profilepic = forwardRef(Profilepic); . Я действительно благодарен вам за то, что вы мне помогаете!! Я твой должник.

2. @Kazim Интересно, я следовал синтаксису/шаблону, используемому в официальных документах React. Вместо этого я обновил свой ответ на прямой экспорт forwardRef(Profilepic) . Я подозреваю, что у этого не будет такой проблемы.

3. @Kazim Я думаю, что все части есть, но мне, возможно, потребуется на самом деле создать образец демонстрационного кода и коробки, чтобы протестировать его. Однако уже очень поздно, так что с этим придется подождать до утра. Я буду сообщать вам о любых обновлениях.