#javascript #reactjs #react-hooks #use-effect #use-state
Вопрос:
Я в основном создаю приложение React, которое имитирует Craigslist. Вошедший в систему пользователь может просматривать компоненты, которые являются товарами для продажи или услугами.
Пользователь может нажать на компонент, чтобы получить подробную информацию, которая также отображает форму комментария. Когда форма отправлена, свойство объекта продажи «комментарии» обновляется. Но поскольку ссылка не обновляется, функция useEffect() не вызывает повторной визуализации. Новый комментарий отображается при обновлении вручную.
Я знаю, что мне, вероятно, нужно создать новую ссылку с помощью .map() и присвоить состояние новой ссылке, но я не смог успешно сделать это правильно.
Крючок возвращает объект, подобный этому (с массивом объектов «комментарии» внутри):
{
"sale": {
"itemName": "Legos",
"itemInfo": "Dont step on them!",
"price": 33,
"postedBy": testUser,
"likedBy": null,
"createdAt": "2021-06-15T13:20:16.508Z",
"comments": [
{
"commentText": "How many?",
"postedBy": "davey",
"createdAt": "2021-06-17T16:52:55.926Z",
"id": 39
},
{
"commentText": "Could you come down on price?!",
"postedBy": "testUser2",
"createdAt": "2021-06-17T17:14:48.155Z",
"id": 40
}
]
}
}
Вот мой код, который вызывает useEffect():
function SalesDetail() {
const { id } = useParams();
const currentUser = useContext(UserContext);
const route = 'sales'
const [sale, setSale] = useState()
useEffect(function getSaleById() {
async function getSale(){
let sale = (await BoonelistApi.getSale(id))
setSale(sale)
}
getSale();
}, [id]);
Я пытался сделать продажу.комментирует зависимость в крючке, но до сих пор, кажется, не могу осознать это и поговорку «Не изменяй состояние». Я также рассматривал подобные проблемы здесь, в стеке, но не смог заставить их работать на меня.
Любая помощь будет очень признательна, и, пожалуйста, дайте мне знать, если потребуется более подробная информация.
Комментарии:
1. Изменяется ли значение
id
константы в вашем компоненте при появлении нового комментария?2.
the Sale object property 'comments' is updated. But since the reference is not updated, useEffect() does not trigger a re-render.
Можете ли вы показать, как вы обновляете комментарии?3. Идентификатор берется из параметров, чтобы указать ссылку на товар продажи в базе данных как sales_id. Каждый sales_comment также получает свой собственный уникальный идентификатор.
Ответ №1:
Вы можете использовать шаблон поставщика для повторного рендеринга. Следуйте приведенным ниже строкам кода, я думаю, это вам немного поможет
// Provider.js
const SaleContext = createContext({
sale :{},
getSale :()=>{},
setSaleId :()=>{}
});
const SaleProvider = ({children})=>{
const [id,setId] = useState('') // string or number
const [sale,setSale] = useState({})
const getSaleById = async (id) =>{
let sale = (await BoonelistApi.getSale(id));
return sale;
}
const getSale = (id) => setSale(getSaleById(id));
const setSaleId = id => setId(id);
useEffect(()=>{
getSale(id);
},[id])
return (
<SaleContext.Provider values = {{
sale,
getSale,
setSaleId
}}>
{children}
</SaleContext.Provider>
)
}
export default SaleProvider;
function SalesDetail() {
const [saleList, setSale] = useState();
const { id } = useParams();
const {sale,getSale,setSaleId} = useContext(SaleContext);
const currentUser = useContext(UserContext);
const route = 'sales'
const getSaleById = () => {
setSaleId(id);
setSale(sale)
} // every time this function gets called the useEffect will trigger in the provider.js
<SaleProvider>
App.js
</SaleProvider>
Подробнее о шаблоне поставщика. Я думаю, это тебе немного помогло. Кроме того, вы можете использовать Redux или Saga для управления своими состояниями.
Комментарии:
1. Большое спасибо. Я думаю, что это сработало бы, но я решил просто позвонить getSale(id) вручную при отправке формы. У меня немного не хватает времени для этого представления, и я решил пойти с этим, но я добавляю ваш ответ в свои заметки, потому что мне также нужно больше практики с useContext. Еще раз спасибо!
Ответ №2:
Похоже, вы отказываетесь от «продажи» государственной собственности. React не обнаружит обновленное состояние и не выполнит повторную визуализацию при изменении вложенного объекта состояния (в данном случае свойство «комментарии»). Есть много структур, с которыми вы могли бы работать, чтобы получить желаемую повторную визуализацию, просто имейте в виду, что изменение реквизитов компонента всегда вызовет повторную визуализацию, и состояние лучше всего использовать в качестве плоских не вложенных пар ключ:значение. Я бы создал компонент «комментарии» для каждого элемента продажи и передал данные через реквизит из родительского элемента продажи <Comments comments={sale.comments}/>
.
Ответ №3:
Есть ли причина, по которой вы не можете вызвать функцию getSale
вручную после отправки формы ? (без useEffect
).
Иногда useEffect
злоупотребляет.
Вот соответствующая цитата из Дэна Абрамова
Подводя итог, если что-то произойдет из-за того, что пользователь что-то сделал, useEffect может оказаться не лучшим инструментом.
С другой стороны, если эффект просто синхронизирует что-то (координаты карты Google на виджете) с текущим состоянием, useEffect-хороший инструмент. И он может безопасно перегорать.
Комментарии:
1. Огромное спасибо. Я новичок в реагировании (очевидно), и это было такое простое решение и отличный пример того, как вы можете переосмыслить свой ответ, пытаясь сделать что-то необычное.