Как принудительно перерендерить компонент React по нажатию кнопки

Я делаю что-то похожее на приложение с фильмами. У меня с самого начала на сайте выводятся некоторые фильмычто есть уже

а также несколько инпутов. Когда пользователь их ввёл и нажал кнопку они должны поместиться в новый объект в массив с фильмами и вывестись. Когда же я всё заполняю и нажимаю кнопку, то ничего не происходит. Я так понимаю это из-за того, что список не перерендерился. Но не понимаю как это исправить.

Массив:

export let filmsData = [
    {
        name: 'Death book', 
        year: 2007,
        censure: '16+',
        country: 'Japan',
        time: '145min'
    },
    {
        name: '1+1',
        year: 2012,
        censure: '12+',
        country: 'USA',
        time: '120min'
    },
    {
        name: 'Gran Turismo',
        year: 2023,
        censure: '18+',
        country: 'USA',
        time: '134min'
    },
    {
        name: 'Matrix',
        year: 1991,
        censure: '18+',
        country: 'USA',
        time: '120min'
    }
]

Вывод массива в виде как на прикреплённом фото:

import { filmsData } from '../filmsData'
import styles from './ChangeInput.module.css'

export default function ChangeInput() {
        return (<div>
            {filmsData.map(film => {
                return (
                    <div className={styles.filmPlace} key={film.name}>
                     <h3 className={styles.title}>{film.name}</h3>
                     <br />
                     <h5 className={styles.yearAndCensure} >{film.year}</h5>
                     <h5 className={styles.yearAndCensure} >{film.censure}</h5>
                     <br />
                     <h4 className={styles.countryAndTime} >{film.country}</h4>
                     <h4 className={styles.countryAndTime} >{film.time}</h4>
                    </div>
                    )
            })
            }
        </div>)
    }

Обработка инпутов:

import React from "react";
import { filmsData } from "./filmsData";

export function AddListEl() {
    let FirstInput = document.getElementById('FirstInput');
    let SecondInput = document.getElementById('SecondInput');    
    let ThirdInput = document.getElementById('ThirdInput');
    let FourthInput = document.getElementById('FourthInput');
    let FifthInput = document.getElementById('FifthInput');
    function AddListItem() {
        filmsData.push({
            name: `${FirstInput.value}`,
            year: `${SecondInput.value}`,
            cenzure: `${ThirdInput.value}`,
            country: `${FourthInput.value}`,
            time: `${FifthInput.value}`
        })
    }

    return (
    <section>
     <input placeholder="name" type="text" id="FirstInput" />
     <input placeholder="year" type="number" id="SecondInput" />
     <input placeholder="cenzure" type="text" id="ThirdInput" />
     <input placeholder="country" type="text" id="FourthInput" />
     <input placeholder="time" type="text" id="FifthInput" />
     <button onClick={AddListItem}>Add film</button>
    </section>
   )
}

App.jsx

import './App.css'
import ChangeInput from './ChangeInput/ChangeInput'
import { AddListEl } from './FormInput'
function App() {
  return (
    <>
    <AddListEl/>
    <ChangeInput />
    </>
  )
}
export default App

Ответы (1 шт):

Автор решения: SwaD

Ничего не надо принудительно рендерить. надо просто правильно менять данные в реакте.

Реакт сам обновляем данные при изменении состояния.
Первое что надо сделать, это массив с данными положить в состояние компонента App.
Второе, это отдавать данное состояние дочерним компонентам в качестве пропсов(параметров). В вашем случае это компонент ChangeImport
Третье, передать функцию изменения состояния в компонент AddListEl, что бы добавлять новые данные.

import React, { useState } from 'react';
import {filmsData} from './const'
import ChangeImport from './ChangeInput';
import { AddListEl } from './AddListEl'

export default function App(props) {
  const [films, setFilms] = useState([ ...filmsData ]);
  return (
    <div className='App'>
      <hr />
      <AddListEl addFilm={setFilms} />
      <ChangeImport films={films} />
    </div>
  );
}

Теперь AddListEl приведем в порядок и сделаем возможным добавление новых данных:

Первое, избавимся от document.getElementById. Далее создадим массив с нужными инпутами, что бы не дублировать код и функцию обновления состояния инпутов. Все элементы ввода должны контролироваться реактом.

import React, { useState } from "react";
const fileds = [
  {
    plaseHolder: 'name',
    type: 'text',
    id: 'FirstInput',
    value: ''
  },
  {
    plaseHolder: 'year',
    type: 'number',
    id: 'SecondInput',
    value: ''
  },
  {
    plaseHolder: 'cenzure',
    type: 'text',
    id: 'ThirdInput',
    value: ''
  },
  {
    plaseHolder: 'country',
    type: 'text',
    id: 'FourthInput',
    value: ''
  },
  {
    plaseHolder: 'time',
    type: 'text',
    id: 'FifthInput',
    value: ''
  },
];

export function AddListEl({ addFilm }) {
    const [fields, setFields] = useState([ ...fileds ]);

    function changeInput(idx, value) {
      const inputs = [ ...fields ];
      inputs[idx].value = value;
      setFields(inputs);
    }
  
    function AddListItem() {
        addFilm(prev => {
          prev.push({
            name: fields[0].value,
            year: +fields[1].value,
            censure: fields[2].value,
            country: fields[3].value,
            time: fields[4].value
          });
          return [ ...prev ];
        });
    }

    return (
    <section>
      {fields.map((field, idx) => <input 
                                    placeholder={field.plaseHolder} 
                                    type={field.type} 
                                    id={field.id} 
                                    onChange={(e) => changeInput(idx, e.target.value)} 
                                      />
                 )
      }
      
     <button onClick={AddListItem}>Add film</button>
    </section>
   )
}

В компоненте ChangeInput добавим пропсы ChangeInput({ films }) и изменим рендер на films.map(film

import React from "react";
import { styles } from './const';

export default function ChangeInput({ films }) {
  console.log('render', films);
        return (<div>
            {films.map(film => {
                return (<>
                    <div className={styles.filmPlace} key={film.name}>
                     <h3 className={styles.title}>{film.name}</h3>
                     <br />
                     <h5 className={styles.yearAndCensure} >{film.year}</h5>
                     <h5 className={styles.yearAndCensure} >{film.censure}</h5>
                     <br />
                     <h4 className={styles.countryAndTime} >{film.country}</h4>
                     <h4 className={styles.countryAndTime} >{film.time}</h4>
                    </div>
                  <hr />
                  </>
                    )
            })
            }
        </div>)
    }

Теперь, при добавлении новых данных в массив, реакт будет перерисовывать список.

Проверить можно в песочнице

→ Ссылка