Страница не обновляется при изменении данных на ней
У меня есть страница на которой выводятся все картинки из массива в котором сохранены url картинок. На этой странице есть иконка при нажатии на которую открывается модальное окно в котором нужно ввести url картинки, после чего при нажатии на кнопку сохранить введенный url добавляется в массив в котором хранятся все url. Проблема в том, что мне приходится в навбаре нажимать на ссылку которая открывает страницу в которой отображаются эти картинки из массива, чтобы новая картинка появилась на страницу, хотя все должно отображаться сразу же после добавления в массив
Это код страницы на которой выводятся все фотографии:
import React, { useState, useEffect } from 'react'
import './Photos.css'
import { AddPhoto } from '../components/AddPhoto'
export const Photo: React.FC = () => {
const [photos, setPhotos] = useState<string[]>([]);
useEffect(() => {
localStorage.setItem('photos', JSON.stringify(photos))
}, [photos])
useEffect(() => {
const saved = JSON.parse(localStorage.getItem('photos') || '[]')
setPhotos(saved)
}, [])
return (<>
<div className='addPhotoBtn' >
<AddPhoto photos={photos} />
</div>
<div className="gallery" >
{photos.map(item =>
<div className="img-item" >
<img src={item} alt="" className="img" />
</div>
)}
</div>
</>)
}
и код модального окна в которой в качестве props передается сам массив который хранит url
import React, { useState } from 'react'
import { Button, Modal } from 'react-bootstrap'
import './AddPhoto.css'
type AddPhoto = {
// addPhoto(url: string): void
photos: string[],
}
export const AddPhoto: React.FC<AddPhoto> = ({ photos }) => {
const [input, setInput] = useState<string>('')
const [show, setShow] = useState(false);
// const [file, setFile] = useState<string[]>([]) //сохранение url картинки
const handleClose = () => {
setShow(false);
}
const handleShow = () => setShow(true);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInput(e.target.value);
console.log(input)
}
const UploadFile = () => {
photos.push(input)
// addPhoto(input);
setInput('');
setShow(false);
}
return (<>
<svg onClick={handleShow} id="plus-icon" fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24px" height="24px"><path d="M 11 2 L 11 11 L 2 11 L 2 13 L 11 13 L 11 22 L 13 22 L 13 13 L 22 13 L 22 11 L 13 11 L 13 2 Z" /></svg>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<div className="upload-icon">
<div className="urlContainer">
<input type="text" className="urlInput" onChange={handleChange} />
</div>
</div>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={UploadFile}>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</>)
}
Ответы (1 шт):
React.useState и массивы
- необходимо передавать новый объект массива
const [array, setArray] = useState(['']) const newArray = [...array] newArray.push('') setArray(newArray) - необходимо передавать в "компонент контроллер"
setArray
Пример для запуска
const{useState:useState}=React;var data;!function(t){let e,a,n;!function(t){t.initState=(({str:t="",dataList:e}={})=>useState(e||[{str:t,id:0}]))}(e=t.model||(t.model={})),function(t){t.Component=(({list:t})=>React.createElement("ul",null,t.map(({str:t,id:e})=>React.createElement("li",{key:e}," ",t," "))))}(a=t.vue||(t.vue={})),function(t){t.Component=(({dataState:t})=>{const[e,a]=t,[n,l]=useState("");return React.createElement(React.Fragment,null,React.createElement("input",{type:"text",onInput:t=>{const e=t.target.value;l(e)}}),React.createElement("br",null),React.createElement("button",{onClick:()=>{let t=[...e];t.push({str:n,id:e.length}),a(t)}},"add"),React.createElement("br",null),n)})}(n=t.controller||(t.controller={}))}(data||(data={}));const App=()=>{const t=data.model.initState();return React.createElement(React.Fragment,null,React.createElement(data.vue.Component,{list:t[0]}),React.createElement(data.controller.Component,{dataState:t}))};ReactDOM.render(React.createElement(App,null),document.body);
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
Код
ВНИМАНИЕ!
В этом примере используется labeled tuple elements (TS 4+).
Подробности там и тут
import React from 'react'
import ReactDOM from 'react-dom'
// -,-
// -,-
// FIXME: import React, { useState } from 'react'
const {useState} = React
namespace data {
export namespace model {
export type data = {
str: string,
id: number,
}
export type dataList = data[]
export type setList = React.Dispatch<React.SetStateAction<dataList>>
// TS - 4.0+ (named tuple)
export type dataState = [list: dataList, setList: setList]
type _initState = (props?: {
str?: string,
dataList?: dataList,
}) => dataState
export const initState: _initState = ({ str = '', dataList } = {}) => useState(dataList ? dataList : [{ str, id: 0 }] as dataList)
}
export namespace vue {
type _props = {
list: model.dataList,
}
export const Component: React.FC<_props> = ({ list }) => (
<ul>
{list.map(({ str, id }) => (
<li key={id} > {str} </li>
))}
</ul>
)
}
export namespace controller {
type _props = {
dataState: model.dataState
}
export const Component: React.FC<_props> = ({ dataState }) => {
const [list, setList] = dataState
/**
* FIXME: (1) если не используется внутри еомпронента - то `useState` не нужен
* замени на let value = ''
*/
const [value, setValue] = useState('')
const add = () => {
let newList = [...list]
newList.push({ str: value, id: list.length })
setList(newList)
}
const onInput = (e: React.FormEvent<HTMLInputElement>) => {
const el: HTMLInputElement = e.target as any
const value = el.value
// FIXME: (1) -,-
setValue(value)
}
return (<>
<input type="text" onInput={onInput} /><br />
<button onClick={add}>add</button><br />
{value /*FIXME: (1) -,-*/}
</>)
}
}
}
const App: React.FC = () => {
const dataState = data.model.initState()
return (<>
<data.vue.Component list={dataState[0]} />
<data.controller.Component dataState={dataState} />
</>)
}
ReactDOM.render(<App />, document.body)