Каково решение для пересчета функции в компоненте, если компонент был создан?
Проблема в том, что когда я нажимаю кнопку, функция test всегда имеет массив тегов по умолчанию со значением [], а не обновляется.
Песочница пример .
Нужно ли заново создавать searchBlock, если теги были изменены?
export default function Home() {
const [tags, tagsSet] = useState([])
const [searchBlock, searchBlockSet] = useState(false)
useEffect(() => {
let tempBlock = <button onClick={test}>{'doesnt work. Its like test function with current values saved somewhere in momery'}</button>
searchBlockSet(tempBlock)
}, [])
console.log(tags) // will give updated tags array here [{"name":"x","description":"y"}, ...and so on for every click]
function test() {
console.log(tags) // tags here will always be [], but should be [{"name":"x","description":"y"}, ...and so on for every click, after first click]
let newTags = JSON.parse(JSON.stringify(tags))
newTags.push({
name: 'x',
description: 'y'
})
tagsSet(newTags)
}
return (
<div>
<button onClick={test}>this works fine</button>
{searchBlock}
{JSON.stringify(tags)} //after first click and next once will be [{"name":"x","description":"y"}] but should be [{"name":"x","description":"y"},{"name":"x","description":"y"},{"name":"x","description":"y"}]
</div>
)
}
Полный код, если приведенного выше упрощенного рабочего примера достаточно:
export function TagsAdd({
tags,
tagsSet,
book,
tagsAddShow,
tagsAddShowSet,
roleAdd
}) {
const { popupSet } = useContext(PopupContext)
const { profileSet, profile } = useContext(ProfileContext)
const [searchTerm, searchTermSet] = useState('')
const [searchBlock, searchBlockSet] = useState([])
useEffect(() => {
if (searchTerm.length < 1) return
const timeout = setTimeout(() => {
tagSearch(searchTerm)
}, 2000)
return () => clearTimeout(timeout)
}, [searchTerm])
async function tagSearch(value) {
let res = await fetch('api/tag_seatch/' + value)
res = await res.json()
if (res.error) return popupSet(res)
if (res.tags[0]) {
searchBlockCalculate(res.tags)
}
}
function searchBlockCalculate(search) {
let tempBlock = search
.filter(({ id }) => {
return !tags.some(tag => {
return tag.id == id
})
})
.map(tag => {
return (
<Button key={tag.id} onClick={handleTagAdd(tag.id, tag.name, tag.description)}>
{tag.name}
</Button>
)
})
searchBlockSet(tempBlock)
}
let handleTagAdd = (tagId, name, description) => async () => {
let res = await fetch('api/book_tag_add', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
role: roleAdd,
bookId: book.id,
tagId: tagId
})
})
res = await res.json()
if (res.error) return popupSet(res)
// tags always default and not updated version
let newTags = JSON.parse(JSON.stringify(tags))
newTags.push({ id: tagId, name: name, description: description, likes: 1 })
tagsSet(newTags)
profileSet(Object.assign(JSON.parse(JSON.stringify(profile)), res.profile))
}
function handleInput(e) {
searchTermSet(e.target.value)
}
return (
<>
{tagsAddShow && (
<div>
<Input value={searchTerm} onChange={handleInput} />
{searchBlock}
</div>
)}
</>
)
}
Это будет работать, если я добавлю:
const [lastSearch, lastSearchSet] = useState(false)
useEffect(() => {
if (lastSearch) searchBlockCalculate(lastSearch)
}, [tags])
async function tagSearch(value) {
let res = await fetch('api/tag_seatch/' + value)
res = await res.json()
if (res.error) return popupSet(res)
if (res.tags[0]) {
searchBlockCalculate(res.tags)
}
lastSearchSet(res.tags) //added
}