Я пытаюсь преобразовать эту классную <canvas>
анимацию, которую я нашел здесь, в повторно используемый компонент React. Похоже, для этого компонента потребуется один родительский компонент для холста и множество дочерних компонентов для function Ball()
.
По соображениям производительности, вероятно, было бы лучше сделать Balls
компоненты без сохранения состояния, поскольку их будет много. Я не так хорошо знакомы с созданием компонентов без гражданства , и было интересно , где я должен определить this.update()
и this.draw
функции, определенные в function Ball()
.
Идут ли функции для компонентов без состояния внутри компонента или снаружи? Другими словами, что из перечисленного лучше?
1:
const Ball = (props) => {
const update = () => {
...
}
const draw = () => {
...
}
return (
...
);
}
2:
function update() {
...
}
function draw() {
...
}
const Ball = (props) => {
return (
...
);
}
Каковы плюсы и минусы каждого из них и один из них лучше для конкретных случаев использования, таких как мой?
Ответы:
Прежде всего следует отметить, что функциональные компоненты без состояния не могут иметь методов, вы не должны рассчитывать на вызов
update
илиdraw
визуализацию,Ball
если это функциональный компонент без состояния.В большинстве случаев вам следует объявлять функции вне функции компонента, поэтому вы объявляете их только один раз и всегда повторно используете одну и ту же ссылку. Когда вы объявляете функцию внутри, каждый раз при визуализации компонента функция будет определяться снова.
Бывают случаи, когда вам нужно определить функцию внутри компонента, например, назначить ее в качестве обработчика событий, который ведет себя по-разному в зависимости от свойств компонента. Но все же вы можете определить функцию снаружи
Ball
и связать ее со свойствами, сделав код намного чище и сделав функцииupdate
илиdraw
многоразовыми.// You can use update somewhere else const update (propX, a, b) => { ... }; const Ball = props => ( <Something onClick={update.bind(null, props.x)} /> );
Если вы используете хуки , вы можете использовать их,
useCallback
чтобы гарантировать, что функция переопределяется только при изменении одной из ее зависимостей (props.x
в данном случае):const Ball = props => { const onClick = useCallback((a, b) => { // do something with a, b and props.x }, [props.x]); return ( <Something onClick={onClick} /> ); }
Это неправильный путь :
const Ball = props => { function update(a, b) { // props.x is visible here } return ( <Something onClick={update} /> ); }
При использовании
useCallback
определениеupdate
функции в самомuseCallback
хуке, за пределами компонента, становится дизайнерским решением больше, чем что-либо, вы должны принять во внимание, собираетесь ли вы повторно использоватьupdate
и / или если вам нужно получить доступ к области закрытия компонента, чтобы, например, чтение / запись в состояние. Лично я предпочитаю определять его внутри компонента по умолчанию и делаю его повторно используемым только в случае необходимости, чтобы предотвратить чрезмерную разработку с самого начала. Вдобавок ко всему, повторное использование логики приложения лучше выполнять с помощью более конкретных хуков, оставляя компоненты для презентационных целей. Определение функции вне компонента при использовании хуков действительно зависит от степени разделения от React, которую вы хотите для логики вашего приложения.источник
this.draw
функцией внутриBall
. Он используетctx
от того, что было бы родительским,<canvas>
а также используетthis
ключевое слово для того, что будет дочернимBall
компонентом. Каким будет лучший способ интеграции реализации компонента без сохранения состояния, чтобы оба эти свойства были доступны?this
при использовании без гражданства функциональных компонентов, имеют в виду. Что касается контекста холста, вам придется передать его каждомуBall
, что совсем не очень хорошо.bind
конкретно в Chrome до 59 года было даже медленнее, чем функции стрелок. И в Firefox тоже довольно долго, поскольку они оба работают с одинаковой скоростью. Так что я бы сказал, что в таких случаях нет разницы, какой путь предпочтительнее :)Something
компонента знать, что в его родительском компоненте есть свойство X, поскольку он сообщает ему о своем контексте. То же самое происходит с вопросом, который вы задаете, и с образцом кода, который я написал, это зависит от контекста, который для простоты игнорируется.У нас могут быть функции внутри функциональных компонентов без состояния, пример ниже:
const Action = () => { function handlePick(){ alert("test"); } return ( <div> <input type="button" onClick={handlePick} value="What you want to do ?" /> </div> ); }
Но это не очень хорошая практика, так как функция
handlePick()
будет определяться каждый раз при вызове компонента.источник
handlePick()
над / вне компонента, какfunction handlePick() { ... }; const Action = () => { ... }
результат, что handlePick определяется только один раз. Если вам нужны данные изAction
компонента, вы должны передать их в качестве параметровhandlePick
функции.Мы можем использовать перехватчик React,
useCallback
как показано ниже, в функциональном компоненте:const home = (props) => { const { small, img } = props const [currentInd, setCurrentInd] = useState(0); const imgArrayLength = img.length - 1; useEffect(() => { let id = setInterval(() => { if (currentInd < imgArrayLength) { setCurrentInd(currentInd => currentInd + 1) } else { setCurrentInd(0) } }, 5000); return () => clearInterval(id); }, [currentInd]); const onLeftClickHandler = useCallback( () => { if (currentInd === 0) { } else { setCurrentInd(currentInd => currentInd - 1) } }, [currentInd], ); const onRightClickHandler = useCallback( () => { if (currentInd < imgArrayLength) { setCurrentInd(currentInd => currentInd + 1) } else { } }, [currentInd], ); return ( <Wrapper img={img[currentInd]}> <LeftSliderArrow className={currentInd > 0 ? "red" : 'no-red'} onClick={onLeftClickHandler}> <img src={Icon_dir + "chevron_left_light.png"}></img> </LeftSliderArrow> <RightSliderArrow className={currentInd < imgArrayLength ? "red" : 'no-red'} onClick={onRightClickHandler}> <img src={Icon_dir + "chevron_right_light.png"}></img> </RightSliderArrow> </Wrapper>); } export default home;
Я получаю img от его родителя, и это массив.
источник
Если вы хотите использовать реквизиты или состояние компонента в функции, это должно быть определено в компоненте с помощью useCallback.
function Component(props){ const onClick=useCallback(()=>{ // Do some things with props or state },[]) }
С другой стороны, если вы не хотите использовать свойства или состояние в функции, определите это вне компонента.
const computeSomethings=()=>{ // Do some things with params or side effects } function Component(props){ }
источник