Что это за зависимости?
useEffect
принимает необязательный второй аргумент, который представляет собой массив зависимостей. Зависимости хука useEffect
говорят ему запускать эффект всякий раз, когда его зависимость изменяется.
Если вы не передадите необязательный второй аргумент для хука useEffect, он будет выполняться каждый раз, когда компонент повторно визуализирует . Пустой массив зависимостей указывает, что вы хотите запустить эффект только один раз после первоначального рендеринга компонента. В этом случае ловушка useEffect
будет вести себя почти как componentDidMount в компонентах класса.
почему рекомендуется делать их исчерпывающими?
Эффекты см. props
и state
из рендеринга, в котором они были определены. Поэтому, когда вы используете что-то из области функционального компонента, который участвует в потоке данных реакции, например реквизиты или состояние, внутри функции обратного вызова хука useEffect
, эта функция функции обратного вызова закрывается над этими данными, и если новый эффект не определен с новыми значениями props и state, ваш эффект будет видеть устаревшие props и значения состояния.
Следующий фрагмент кода демонстрирует, что может go неправильно, если вы l ie о зависимостях хука useEffect
.
В следующем фрагменте кода есть два компонента: App
и User
. Компонент App
имеет три кнопки и поддерживает идентификатор пользователя, который отображается компонентом User
. Идентификатор пользователя передается как опора из App
в User
компонент, а User
компонент выбирает пользователя с идентификатором, переданным как опора, из jsonplaceholder
API.
Теперь проблема в следующий фрагмент кода говорит о том, что он работает неправильно. Причина в том, что это ложь о зависимости хука useEffect
. useEffect
hook зависит от userID
prop для получения пользователя из API, но поскольку я пропустил добавление userID
в качестве зависимости, useEffect
hook не выполняется каждый раз, когда userID
prop изменяется.
function User({userID}) {
const [user, setUser] = React.useState(null);
React.useEffect(() => {
if (userID > 0) {
fetch(`https://jsonplaceholder.typicode.com/users/${userID}`)
.then(response => response.json())
.then(user => setUser(user))
.catch(error => console.log(error.message));
}
}, []);
return (
<div>
{user ? <h1>{ user.name }</h1> : <p>No user to show</p>}
</div>
);
}
function App() {
const [userID, setUserID] = React.useState(0);
const handleClick = (id) => {
setUserID(id);
};
return(
<div>
<button onClick={() => handleClick(1)}>User with ID: 1</button>
<button onClick={() => handleClick(2)}>User with ID: 2</button>
<button onClick={() => handleClick(3)}>User with ID: 3</button>
<p>Current User ID: {userID}</p>
<hr/>
<User userID={userID} />
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Приведенный выше фрагмент кода показывает одну из немногих проблем, которые могут возникнуть, если вы ie о зависимостях, и вот почему вы не должны пропускать или l ie о зависимостях ловушки useEffect
или любой другой ловушки, которая имеет массив зависимостей, например useCallback
hook. '
Чтобы исправить предыдущий фрагмент кода , вам просто нужно добавить userID
как зависимость к массиву зависимостей хука useEffect
, чтобы if выполнялся всякий раз, когда userID
prop изменяется, и новый пользователь выбирается с идентификатором, равным userID
prop.
function User({userID}) {
const [user, setUser] = React.useState(null);
React.useEffect(() => {
if (userID > 0) {
fetch(`https://jsonplaceholder.typicode.com/users/${userID}`)
.then(response => response.json())
.then(user => setUser(user))
.catch(error => console.log(error.message));
}
}, [userID]);
return (
<div>
{user ? <h1>{ user.name }</h1> : <p>No user to show</p>}
</div>
);
}
function App() {
const [userID, setUserID] = React.useState(0);
const handleClick = (id) => {
setUserID(id);
};
return(
<div>
<button onClick={() => handleClick(1)}>User with ID: 1</button>
<button onClick={() => handleClick(2)}>User with ID: 2</button>
<button onClick={() => handleClick(3)}>User with ID: 3</button>
<p>Current User ID: {userID}</p>
<hr/>
<User userID={userID} />
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>
В вашем случае, если вы пропустите добавление props.userID
в массив зависимостей хука useEffect
, ваш эффект не будет получать новые данные, когда опора userID
изменений.
Чтобы узнать больше о негативных последствиях исключения зависимостей хука useEffect
, см .:
Как я могу аккуратно решить мой случай?
Поскольку ваш эффект зависит от значения prop userID
, вы должны включить он в массиве зависимостей, чтобы всегда получать новые данные при изменении userID
.
Добавление props.userID
в качестве зависимости к useEffect
хук будет вызывать эффект каждый раз, когда props.userID
изменяется, но проблема в что вы без необходимости используете username
внутри useEffect
. Вы должны удалить его, потому что в этом нет необходимости, поскольку значение username
не определяет и не должно определять, когда должны быть получены новые данные пользователя. Вы просто хотите, чтобы эффект запускался всякий раз, когда изменяется props.userID
.
Вы также можете отделить действие от обновления состояния, используя ловушку useReducer
для управления и обновления состояния.
Редактировать
Поскольку вы хотите запустить эффект только тогда, когда userID
используется ловушкой useEffect
, в вашем случае можно иметь пустой массив в качестве второго аргумента и игнорировать предупреждение eslint. Вы также можете не опускать какие-либо зависимости хука useEffect
и использовать какое-то условие в useEffect
хуке, которое оценивается как false после первого запуска эффекта и обновляет состояние.
Лично я бы посоветовал вам чтобы попытаться изменить структуру ваших компонентов, чтобы вам не приходилось сталкиваться с подобными проблемами в первую очередь.