React: не обрабатывать useEffect при первой отрисовке компонента
есть такой компонент:
// компонент "выпадающий список"
const DropdownList = (props: IProps_DropdownList) => {
// контроль состояний
const [values, setValues] = useState(props.values); // выбранные элементы
// эффект: изменен выбор элементов выпадающего списка
useEffect(() => {
props.onChange?.(values);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [values, props.onChange])
// остальная логика
return <></>
}
в компоненте при разных ситуациях изменяется значение values
это значение должно затем передаться вовне
чтоб код передачи не таскать по всему компоненту использую useEffect и когда знамение меняется, то оно передаётся наружу через вызов колбэка props.onChange?.(values)
При этом при создании компонента, установки состояния values
сразу же срабатывает и useEffect
, т.е. я всегда дергается колбэк, а мне этого не надо.
Как можно избежать такого поведения?
При этом очень не хотелось бы:
- использовать дополнительные состояния использовать колбэк в разных
- частях компонента
Ответы (2 шт):
Автор решения: ksa
→ Ссылка
не обрабатывать useEffect при первой отрисовке компонента
Например вот так...
const DropdownList = props => {
const ref = React.useRef(null);
const [values, setValues] = React.useState(props.values);
React.useEffect(_ => {
console.log('useEffect')
if (ref.current) {
console.log('onChange')
if (props.onChange) props.onChange(values);
} else {
ref.current = true
console.log('Ничего не случилось...')
}
}, [values, props.onChange])
const act = e => setValues(e.target.value)
return <div>
<input onChange={act} value={values} />
</div>
}
const App = props => {
const [val, setVal] = React.useState(0);
return <div>
<DropdownList values={val} />
</div>
}
const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(domContainer);
root.render(<App />);
<script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
<div id="like_button_container"></div>
Автор решения: SaNFeeD
→ Ссылка
У себя в проекте использую самописный хук.
const useIsFirstRender = () => {
const isFirst = useRef(true)
if (isFirst.current) {
isFirst.current = false
return true
}
return isFirst.current
}
В компонентах используется так.
const Component = (props) => {
const [values, setValues] = useState(props.values);
const isFirst = useIsFirstRender()
useEffect(() => {
if(!isFirst) props.onChange?.(values);
}, [values])
return (<div>Component</div>)
}