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
相关产品推荐
相关产品推荐

