Почему я не вижу родительское состояние из обработчика событий дочернего компонента?

#reactjs

#reactjs

Вопрос:

У меня есть два компонента: еда и ингредиент. Ингредиент всегда является дочерним элементом Meal . Я передаю приведенную ниже функцию каждому ингредиенту в качестве реквизита, например <Ingredient deleteIngFunc={handleDeleteIng} /> .

При нажатии кнопки в ингредиенте срабатывает prop.deleteIngFunc ингредиент, но когда я console.debug ingsArrayCopy из функции, он пуст! Оно не должно быть пустым, потому что состояние явно присутствует при рендеринге страницы (т. Е. Ингредиенты отображаются на странице, поэтому состояние явно не пустое)

Meal.js

 import React, {useState, useEffect} from 'react';
import Ingredient from './Ingredient';

function Meal(props){
    const [ingArray, setIngArray] = useState([]);

    function handleDeleteIng(e){
        let ingsArrayCopy = [...ingArray];
        console.debug(ingsArrayCopy); // empty array??
    }

    async function initIngs(){
        let ings = props.ings.map(
            ing => (
                <Ingredient title={ing.title} id={ing.id} deleteIngFunc={handleDeleteIng} />
            )
        )

        return await setIngArray(prev => ings)
    }

    function updateIngs(newIngObject){
        let oldIngState = [...ingArray];

        let newIng = <Ingredient key={newIngObject.id} id={newIngObject.id} title={newIngObject.title} />

        let newIngState = oldIngState.concat([newIng]);

        setIngArray(prev => newIngState);
    }


    useEffect(
        () => {
            initIngs();
        },
        []
    );

    return (
        <ul>
            {ingArray}
        </ul>
    );
}

export default Meal;
  

Ingredient.js

 import React, {useState, useEffect} from 'react';
import CancelIcon from '@material-ui/icons/Cancel';
import Typography from '@material-ui/core/Typography';
import IconButton from '@material-ui/core/IconButton';

function Ingredient(props){

    function handleDeletion(e){
        e.preventDefault()
        props.deleteIngFunc(e)
    }

    return (
        <li
            key={props.id}
            className="ingredient-listitem"
        >
            <Typography className="ingredient-text">{props.title}</Typography>

            <IconButton onClick={handleDeletion}>
                <CancelIcon></CancelIcon>
            </IconButton>
        </li>
    )
}

export default Ingredient;
  

Комментарии:

1. Можете ли вы сказать мне, какова ценность еды (реквизит)

2. Причина, по которой это происходит, заключается в том, что this изменения зависят от того, откуда вызывается функция, если вы сначала не привязали функцию. Когда функция вызывается внутри ингредиента, this это компонент ингредиента, а не компонент блюда, который вы ожидаете. Это можно исправить, связав функцию с помощью .bind(this) или используя функции со стрелками, но я бы посоветовал вам обновить ваши функции обратного вызова для использования useCallback , чтобы они воссоздавались только тогда, когда им это тоже нужно. React Doc: useCallback

Ответ №1:

Нет, значение состояния не может быть доступно внутри обычной функции. Доступ к нему возможен только через следующие перехватчики реакции useEffect() useCallback() useMemo() и return инструкцию вашего функционального компонента.

Например:

 function App() {
  const [state, setState] = useState('initial Value')

  function someFunction(){
    // It's not recommended to access the state inside of this function
    // cause the value of the state will always be ('initial Value')
    // even if the state were updated
    console.log(state)
   // Why ?
   // Because regular function like this cannot have dependency array
   // And thus without dependency array function will not know that state has changed
  }

  useEffect(()=>{
    // It's good if you access the value of the state here
    // It will be assured it will always have the updated value
    console.log(state)
  },[state]) 


  return (
    // You can also access the value of the state inside return statement        
    <>
    {console.log(state)}
    <SomeComponent props={state}/>
    </>
  )
}
  

Дополнительно: вы можете установить состояние для обычной функции, но вы не можете получить доступ или прочитать состояние для обычной функции

Я включил ссылку codesandbox для демонстрации, специфичной для вашей проблемы

https://codesandbox.io/s/accessingstate-03hud?file=/src/App.js

Комментарии:

1. Я создал новую функцию, используя useCallback , которая делает то же самое, что и, handleDeleteIng и я передал ее в дочерний компонент. Массив все еще не читается так, как я ожидал.

2. @RobbieS Дважды проверьте, добавляете ли вы значение в массив зависимостей. Вы можете показать мне свой код, если вам нужно

3. codesandbox.io/s/infallible-rhodes-f2qwn?file=/src/testdata.js ; Это может вызвать ошибки зависимости; но если вы обновите мини-браузер, он загрузится правильно

4. Я переработал и переписал ваш код, проверьте это codesandbox.io/s/refactored-react-r3crt?file=/src/Meal.js

5. Я потрясен. Спасибо! Я прочитаю это и узнаю