You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中创建Observer组件:如何向子组件传递内部props?

解决方案

你的需求完全可以实现,核心采用React的Render Props模式即可完成内部状态的透传,你遇到的props.children is not a function报错是因为没有对children的类型做兼容判断:常规用法下children是React节点对象,只有当你往组件内部传入函数作为子元素时,children才是可调用的函数。

1 修改Observer组件

调整组件逻辑,支持函数类型的children,同时补充Observer的销毁逻辑避免内存泄漏,修改后代码如下:

// Observer.js
import React, { useEffect, useRef } from "react";
import { useAnimation } from "framer-motion";

// 新增可配置参数props,提升灵活性
const Observer = ({ children, threshold = 0.1, delay = 0.75, duration = 0.75, once = true }) => {
  const controls = useAnimation();
  const ref = useRef(null);
  const hasAnimated = useRef(false);

  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting && !hasAnimated.current) {
          controls.start({
            opacity: 1,
            transition: { duration, delay },
          });
          // 开启once模式时动画触发后直接取消监听
          if (once) {
            hasAnimated.current = true;
            observer.unobserve(ref.current);
          }
        }
      },
      {
        root: null,
        rootMargin: "0px",
        threshold,
      }
    );
    if (ref.current) {
      observer.observe(ref.current);
    }

    // 组件销毁时清理监听
    return () => {
      if (ref.current) {
        observer.unobserve(ref.current);
      }
      observer.disconnect();
    };
  }, [controls, threshold, delay, duration, once]);

  // 核心:判断children是函数则传入controls调用,否则直接渲染
  return <div ref={ref}>{typeof children === 'function' ? children(controls) : children}</div>;
};

export default Observer;

2 修改子组件用法

将Observer的子元素改为函数形式,接收透传的controls参数绑定到motion元素即可:

// ChildComponent.js
import { motion } from "framer-motion";
import Observer from "./Observer";

const ChildComponent = () => {
  return (
    <Observer>
      {/* 用函数接收controls参数 */}
      {(controls) => (
        <div>
          <motion.div
            initial={{ opacity: 0 }}
            animate={controls}
          >
            <h2>This will animate on scroll</h2>
          </motion.div>
        </div>
      )}
    </Observer>
  );
};

export default ChildComponent;

可选优化方向

  • 针对简单动画场景,可直接在Observer组件内部包裹motion.div,不需要子组件手动绑定controls,进一步简化调用逻辑
  • 可扩展支持更多动画属性的自定义配置,比如位移、缩放等入场动画效果
  • 可增加fallback逻辑,针对不支持Intersection Observer的旧浏览器直接触发动画

内容的提问来源于stack exchange,提问作者Bagseye

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 20:06:02