0

Problem:

I'm using the useContext hook to pass data though the DOM, but the only data that gets passed right now, are the initial values from the ImageContext.

My Findings:

  • The State images in ImageContextProvider holds the correct values (First initial declaration and alter the fetched data).
  • Changing initial values of the state (not the context), findable in the ImageContextProvider, didn't change the output of the useContext hook -> Still just the inital context values were sent
  • Putting everything into one file (to avoid some kind of wrong referencing) didn't fix the problem either
  • Didn't find any similar problem on stack overflow

image_context.js

export const ImageContext = createContext({
    images: [],
    loading: true,
    setImages: () => {},
});


const ImageContextProvider = props => {
    const [images, setImages] = useState({
        images: [],
        loading: true
    }); // Array instead of object

    const fetchData = () => {
        imagesServices.loadImages().then((img) => {
            setImages({
                images: img,
                loading: false
            })
        })
    }

    useEffect(() => {
        fetchData();
    }, []);

    useDebugValue(images ?? 'loading...')
    let value = {images: images.images, loading: images.loading, setImages: setImages}
    return(
    <ImageContext.Provider value={value}>
        {props.children}
    </ImageContext.Provider>
    );
};

export default ImageContextProvider;

visualizer.js

const Visualizer = () => {
    return (
        <ImageContextProvider>
            <Canvas
                camera={{position:  new THREE.Vector3( 0, 0, -0.5 ), fov: 60}}>
                <ambientLight intensity={0.3}/>
                <group>
                    <ImageGroup />
                </group>
                <OrbitControls enableZoom={false} enablePan={false}/>
            </Canvas>
        </ImageContextProvider>
    );
};

export default Visualizer;

image_group.js

const ImageGroup = (props) => {
    const {
        roomID = '0',
        ...restProps
    } = props;
    const {images, loading, setImages} = useContext(ImageContext);

    if (images.loading) return null

    return (
        <Suspense fallback={null}>
            {
                images.map((img) =>
                    (<ImagePlane key={img['imageID']} imgLink={img['imgLink']} position={img['position']}  aspectRatio={img['aspect_ratio']}/>)
                )
            }
        </Suspense>
    );
};

export default ImageGroup;
TheBormann
  • 11
  • 3
  • Syntax-wise this is looking fine to me. Are you sure that the state within the contextprovider changes? – Shaegi Jan 06 '22 at 15:05
  • Thank you, that's good to know. Yeah I'm nearly certain, because I added this code `useEffect(() => {console.log("Called");console.log(images) }, [images])` to the `ImageContextProvider` . With that code, the correct data was printed in the console, but it still didn't get passed to the consumer somehow. – TheBormann Jan 06 '22 at 15:22
  • Can you provide a minimal working example on codepen/codesandbox? – Shaegi Jan 06 '22 at 15:36
  • Something is niggling me because you're returning an object as value rather than the actual state. It may not see it as updated. https://reactjs.org/docs/context.html#caveats That is, maybe it thinks the reference hasn't changed so it doesn't re-render? – Nikki9696 Jan 06 '22 at 15:53
  • @Nikki9696 the problem mentioned in the doc is different. They recommend to lift up the object into the state because the object reference is recreated on every render. To prevent this in functional components you could use e.g. useMemo. In this case the object reference shouldn't be the problem. – Shaegi Jan 06 '22 at 15:57
  • I recreated parts of the Website in Codepen: https://codesandbox.io/s/imagesphere-utvyx – TheBormann Jan 06 '22 at 21:39
  • May be the problem is with export statements in `image_context.js` . You can give it a try by removing `export` keyword in front of `const ImageContext ` . Also remove `export default ImageContextProvider;` And instead, add this line to the bottom: `export { DataContext, DataProvider } ` – Abdulhakim Jan 10 '22 at 19:56
  • Sadly this wasn't the issue – TheBormann Jan 10 '22 at 22:39

1 Answers1

1

The solution to my problem was to put the ImageContextProvider inside the canvas. This is necessary, because elements inside the canvas are using a different context, as explained here: https://github.com/pmndrs/react-three-fiber/blob/master/docs/API/hooks.mdx

TheBormann
  • 11
  • 3