无状态组件中的功能?

Mar*_*ode 42 reactjs

我正在尝试将<canvas>我在这里找到的这个很酷的动画转换为React可重用组件.看起来这个组件需要一个父组件用于画布,并且需要许多子组件function Ball().

出于性能原因,制作Balls无状态组件可能会更好,因为它们会有很多.我对制作无状态组件并不熟悉,并且想知道我应该在哪里定义this.update()和定义的this.draw函数function Ball().

无状态组件的功能是在组件内部还是外部?换句话说,以下哪项更好?

1:

const Ball = (props) => {
    const update = () => {
        ...
    }

    const draw = () => {
        ...
    }

    return (
       ...
    );
}
Run Code Online (Sandbox Code Playgroud)

2:

function update() {
     ...
}

function draw() {
     ...
}

const Ball = (props) => {
    return (
       ...
    );
}
Run Code Online (Sandbox Code Playgroud)

各自的优点/缺点是什么,并且对于像我这样的特定用例更好?

Mar*_*olo 51

首先要注意的是无状态功能组件不能有方法,如果它是无状态功能组件,则不应指望调用updatedraw渲染Ball.

在大多数情况下,您应该在组件函数之外声明函数,因此您只需声明它们一次并始终重用相同的引用.在内部声明函数时,每次渲染组件时,都会再次定义函数.

在某些情况下,您需要在组件内部定义一个函数,例如,将其指定为基于组件属性的行为不同的事件处理程序.但是你仍然可以在外部定义函数Ball并将其与属性绑定,使代码更清晰,并使函数updatedraw函数可重用.

// You can use update somewhere else
const update (propX, a, b) => { ... };

const Ball = props => (
  <Something onClick={update.bind(null, props.x)} />
);
Run Code Online (Sandbox Code Playgroud)

代替:

const Ball = props => {
  const onClick = useCallback((a, b) => {
    // do something with a, b and props.x
  }, [props.x]);

  return (
    <Something onClick={onClick} />
  );
}

Run Code Online (Sandbox Code Playgroud)

  • @MarcoScabbiolo 不不,这不是我的情况,已经在本地使用箭头函数很长时间了,因为唯一不支持它们的浏览器是 IE。实际上,我设法从 [一篇文章](https://medium.com/@mharrisonb/hi-what-c​​ode-did-you-use-for-your-benchmarks-4feef58ea5ef) 中找到了这条评论,它实际上声称` bind` 特别是在 59 之前的 **Chrome 中**甚至比箭头函数**慢**。而在 Firefox 中,这也是相当长的一段时间,因为它们都以相同的速度运行。所以我会说在这种情况下,首选方式没有区别:) (2认同)
  • @MauricioAvendaño 无论哪种方式都有效,但对于“Something”组件来说,知道其父组件中有一个 prop X 是一种不好的做法,因为它使它了解其上下文。您提出的问题和我编写的示例代码也会发生同样的情况,它取决于上下文,为了简单起见,上下文被忽略。 (2认同)

Hos*_*adi 9

如果要在函数中使用 props 或组件状态,则应在组件中使用 useCallback 定义。

function Component(props){
  const onClick=useCallback(()=>{
     // Do some things with props or state
  },[])

  return <Something {...{onClick}} />
}
Run Code Online (Sandbox Code Playgroud)

另一方面,如果您不想在函数中使用 props 或 state,请在组件外部定义它。

const computeSomethings=()=>{
   // Do some things with params or side effects
}

function Component(props){
  return <Something {...{onClick}} />
}
Run Code Online (Sandbox Code Playgroud)

对于 HTML 标签,您不需要 useCallback 因为它将在反应端处理并且不会分配给 HTML

function Component(props){
  const onClick=()=>{
     // Do some things with props or state
  }

  return <Something {...{onClick}} />
}
Run Code Online (Sandbox Code Playgroud)

  • 你能举一个在功能组件内部使用钩子方法的例子吗?(未设置状态方法) (5认同)

小智 8

我们可以在无状态功能组件中包含函数,下面是示例:

 const Action = () => {
  function  handlePick(){
     alert("test");
  }
  return (
    <div>
      <input type="button" onClick={handlePick} value="What you want to do ?" />
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

但是,这不是一个好习惯,因为handlePick()每次调用该组件时都会定义函数。

  • 如果不是一个好的做法,那么替代解决方案是什么? (4认同)
  • 如果这不是一个好的实践,那么如何在函数组件内编写函数,这些函数本来是类风格 React 组件中的类方法?这些方法通常需要访问状态,因此必须位于函数内部。 (2认同)

小智 5

我们可以useCallback在功能组件中使用如下所示的 React 钩子:

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;
Run Code Online (Sandbox Code Playgroud)

我从它的父级获取 'img',这是一个数组。