Как принудительно перерендерить компонент 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 шт):
Ничего не надо принудительно рендерить. надо просто правильно менять данные в реакте.
Реакт сам обновляем данные при изменении состояния.
Первое что надо сделать, это массив с данными положить в состояние компонента 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>)
}
Теперь, при добавлении новых данных в массив, реакт будет перерисовывать список.
Проверить можно в песочнице