Как запустить рендеринг данных, которые пользователь вводит в React?

#javascript #reactjs #input #render

#javascript #reactjs #ввод #рендеринг

Вопрос:

В этом приложении данные учащихся извлекаются из API, новые теги могут быть добавлены для каждого учащегося, нажав кнопку «ПЛЮС» на карточке.

ПРОБЛЕМА: теги НЕ отображаются на экране сразу после их ввода. Они будут отображаться только после того, как выпадающий список будет закрыт и открыт снова или если последовательно ввести несколько тегов.

Проект и код можно найти здесь: https://codesandbox.io/s/hatch-frontend-mch-52n67?file=/src/components/views/Card.js:2280-2320

Card.js

 // ...

// Submit Handler function:
const submitNewTagHandler = (e) => {
    e.preventDefault();
    setHasTags(true);
    console.log(tags);
    setHeightState(
       `${content.current.scrollHeight}px`
    );
    setTags([...tags, newTag]);
    updateStudents(tags, index);
    setNewTag('');
  };


//Tag render:
{hasTags amp;amp; <Tags student={student} />}
// Tag input:
<form onSubmit={submitNewTagHandler}>
    <input
    className='​add-tag-input​'
    onChange={(e) => setNewTag(e.target.value)}
    value={newTag}
    type='text'
    placeholder='Add a new tag'
    />
</form>
 

App.js

 // updateStudent is called as update in App.js
// (This updates the main data array called students)
const update = (t, index) => {
    setTags(t);
    setStudents(
      students.map((student, i) => {
        // console.log(i, index);
        if (i === index) {
          console.log(student, tags);
          return { ...student, tags };
        } else {
          return student;
        }
      })
    );
    console.log(students);
  };
 

Tags.js

 const Tags = (props) => {
  return (
    <div className='tags'>
      {props.student.tags.map((tag, index) => {
        return (
          <h3 className='tag' key={index}>
            {tag}{' '}
          </h3>
        );
      })}
    </div>
  );
};
 

Я пробовал разные способы использования useEffect для повторного рендеринга тегов, но пока безуспешно…

Спасибо!

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

1. Хорошо, нп! Я добавлю немного кода!

2. ваш компонент <Tags> — это тот, который генерирует список? Куда передаются ваши теги? Где находится раскрывающийся список компонентов, о котором вы говорите.

3. Дерево компонентов выглядит следующим образом: App.js > DisplayStudentInfo.js > Card.js > Tags.js

4. если вы не возражаете, поскольку вы просите помощи в устранении неполадок, чтобы лучше обозначить коды, например, имя компонента для каждого из кодов, которыми вы делитесь.

5. Коды выглядят нормально, но мы должны посмотреть, что это за компонент, который вы рендерите. Это может быть вызвано тем, что вы неправильно передаете свои реквизиты и т. Д., Если вы не хотите делиться кодами, наша помощь будет ограничена.

Ответ №1:

Хорошо, из-за того, что вы устанавливаете новые теги, используя локальное состояние, а затем передаете реквизиты тегам, вы вызываете ошибки синхронизации, поскольку все состояния react являются асинхронными.

Итак, я обновил коды до useRef, чтобы получить текущие значения, и это должно сработать.

Необходимо внести много изменений. По сути, все ваши коды перепутаны, потому что вы обновляете состояние другим состоянием. (например, u обновляет теги новыми тегами), но newtags не был обновлен с новым значением.

Я также удалил ваш useEffect в App.js , и показал вам, как использовать MEMO вместо этого.

Удалите эти 2 строки

   const [tags, setTags] = useState(student.tags);
  const [newTag, setNewTag] = useState('');
 

Создать новую ссылку на ввод

   const inputRef = useRef()
  const formRef = useRef()
 

Измените ввод на этот

        <input
          className='​add-tag-input​'
          ref = {inputRef} //add this
          //value={newTag} remove this
          type='text'
          placeholder='Add a new tag'
        />
 

затем ваша функция отправки дескриптора

   const submitNewTagHandler = (e) => {
    const value = inputRef.current.value
    e.preventDefault();
    setHeightState(
       `${content.current.scrollHeight}px`
    );
    updateStudents([...student.tags, value], index);
    formRef.current.reset()
  };
 

затем измените эту строку на обновленную строку.

{студент?.теги?.длина> 0 amp;amp; }

Затем вам нужно обновить .map с помощью ключа, иначе он отображается неправильно.

 <Card key={`student-${student.id}`} students={props.students} student={student} index={index} updateStudents={props.updateStudents} />
 

В вашей функции обновления

 const update = (t, index) => {
    setTags(t);
    setStudents((prev) =>
      prev.map((student, i) => {
        // console.log(i, index);
        if (i === index) {
          console.log("prev map", student, t);
          return { ...student, tags: t };
        } else {
          return student;
        }
      })
    );
    console.log(students);
  };
 

Обновите компонент до этого

 const Tags = ({ tags }) => {
  return (
    <div className="tags">
      {tags.map((tag, index) => {
        return (
          <h3 className="tag" key={`tag-${index}`}>
            {tag}{" "}
          </h3>
        );
      })}
    </div>
  );
};
 

Добавьте это, чтобы исправить ваш аккордеон, где ввод становится скрытым.

  useEffect(() => {

    if (setActive) setHeightState(`${content.current.scrollHeight}px`);

  },[props])
 

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

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

1. и ваше поле ввода не исчезло, оно просто скрылось из-за вашего accordion css -> overflow: hidden;

2. Прежде всего, большое ВАМ спасибо!

3.Несколько вопросов… 1) {student?.tags?.length > 0 amp;amp; } Зачем ставить? после student и тегов?

4.2) .filter( ({ tags }) => tagFilter === "" || tags.filter((x) => x.match(new RegExp(tagFilter, "i"))).length > ); — Почему tagFilter === "" || используется? new RegExp создайте регулярное выражение из tagFilter, и match создаст массив совпадающих тегов, правильно?

5. student?.tag?.length используется для предотвращения возникновения ошибки, когда student или student.tags не определены во время первого рендеринга.