Как визуализировать другой компонент с помощью React Hooks - PullRequest
0 голосов
/ 13 марта 2020

У меня есть родительский компонент с оператором if для отображения двух разных типов кнопок.

Что я делаю, при загрузке страницы я проверяю, возвращает ли API массив с именем lectures как пустой или с любые значения:

lectures.length > 0 ? show button A : show button B

Это компонент, называемый основным. js, где оператор if:

lectures.length > 0 
   ? <div onClick={() => handleCollapseClick()}>
       <SectionCollapse open={open} />                                         
     </div>
   : <LectureAdd dataSection={dataSection} />

Компонент LectureAdd отображает знак + , который откроет модальное окно для создания нового заголовка лекции, а SectionCollapse покажет стрелку, чтобы показать / скрыть список элементов.

Лог c прост:
1. При загрузке страницы, если lectures.lenght > 0 равно false, мы показываем знак +, чтобы добавить новую лекцию
ИЛИ
2. Если lectures.lenght > 0 равно true, мы меняем и показываем стрелку коллапса.

Теперь моя проблема возникает, когда я добавляю новую лекцию из дочернего компонента LectureAdd. js

import React from 'react';
import { Form, Field } from 'react-final-form';

// Constants
import { URLS } from '../../../../constants';

// Helpers & Utils
import api from '../../../../helpers/API';

// Material UI Icons
import AddBoxIcon from '@material-ui/icons/AddBox';


export default ({ s }) => {

  const [open, setOpen] = React.useState(false);
  const [ lucturesData, setLecturesData ] = React.useState(0);
  const { t } = useTranslation();



  const handleAddLecture = ({ lecture_title }) => {
    const data = {
      "lecture": {
        "title": lecture_title
      }
    }

    return api
      .post(URLS.NEW_COURSE_LECTURE(s.id), data)
      .then(data => {

        if(data.status === 201) {
          setLecturesData(lucturesData + 1) <=== this doesn't trigger the parent and the button remains a `+` symbol, instead of changing because now `lectures.length` is 1 
        }

      })
      .catch(response => {
        console.log(response)
      });
    }


  return (
    <>
      <Button variant="outlined" color="primary" onClick={handleClickOpen}>
        <AddBoxIcon />
      </Button>

          <Form 
            onSubmit={event => handleAddLecture(event)}
          >
            {
              ({ 
                handleSubmit
              }) => (
              <form onSubmit={handleSubmit}>
                <Field 
                  name='lecture_title'
                >
                  {({ input, meta }) => (
                    <div className={meta.active ? 'active' : ''}>
                      <input {...input} 
                          type='text'
                          className="signup-field-input"
                        />
                    </div>
                  )}
                </Field>

                <Button 
                  variant="contained" 
                  color="primary"
                  type="submit"
                >
                  ADD LECTURE
                </Button>
              </form>
            )}
          </Form>
    </>
  )
}

Я пытался использовать UseEffect для запуска повторного рендеринга на обновление переменной с именем lucturesData, но она не переопределяет родительский компонент.
Есть идеи? Спасибо Джо

1 Ответ

1 голос
/ 14 марта 2020

Общая проблема в React. Отправка данных сверху вниз очень проста, мы просто пропускаем реквизиты. Передача информации из дочерних компонентов не так просто. Пара решений.

  1. Использование обратного вызова (шаблон наблюдателя) Родитель передает реквизит дочернему элементу, который является функцией. Ребенок вызывает функцию, когда происходит что-то значимое. Затем родитель может что-то сделать, когда функция вызывается, например, принудительно выполнить повторный рендеринг.
function Parent(props) {
    const [lectures, setLectures] = useState([]);

    const handleLectureCreated = useCallback((lecture) => {
        // Force a re-render by calling setState
        setLectures([...lectures, lecture]);
    }, []);

    return (
        <Child onLectureCreated={handleLectureCreated} />
    )
}

function Child({ onLectureCreated }) {
    const handleClick = useCallback(() => {
        // Call API
        let lecture = callApi();

        // Notify parent of event
        onLectureCreated(lecture);
    }, [onLectureCreated]);

    return (
        <button onClick={handleClick}>Create Lecture</button>
    )
}
Аналогично решению № 1, за исключением того, что родительский дескриптор обрабатывает вызов API. Преимущество этого заключается в том, что дочерний компонент становится более пригодным для повторного использования, так как он «отключен».
function Parent(props) {
    const [lectures, setLectures] = useState([]);

    const handleLectureCreated = useCallback((data) => {
        // Call API
        let lecture = callApi(data);

        // Force a re-render by calling setState
        setLectures([...lectures, lecture]);
    }, []);

    return (
        <Child onLectureCreated={handleLectureCreated} />
    )
}

function Child({ onLectureCreated }) {
    const handleClick = useCallback(() => {
        // Create lecture data to send to callback
        let lecture = {
            formData1: '',
            formData2: ''
        }

        // Notify parent of event
        onCreateLecture(lecture);
    }, [onCreateLecture]);

    return (
        <button onClick={handleClick}>Create Lecture</button>
    )
}
Используйте инструмент управления центральным состоянием, такой как Redux. Это решение позволяет любому компоненту «прослушивать» изменения данных, например, новые лекции. Я не буду приводить здесь пример, потому что он достаточно глубок.

По сути, все эти решения включают в себя одно и то же решение, выполненное немного по-разному. Во-первых, используется умный ребенок, который уведомляет своего родителя о событиях после их завершения. Во-вторых, используются немые дети для сбора данных и уведомления родителя о принятии мер в отношении этих данных. Третий, использует централизованную систему управления государством.

...