Как использовать компонент в useContext React?

Структура проекта как на скрине ниже: stage - это сцена из KonvaJS; layer и rect - также объекты конвы; control block - это просто div с кнопками внутри.

Я не могу понять как мне сделать так, чтобы при нажатии на кнопку в правом блоке менялся цвет у rect в левом с помощью useContext.

Сделал так в App

import React, {useRef, useState} from "react";
import LeftBlockfrom "../LeftBlock/LeftBlock";
import ControlBlock from "../ControlBlock/ControlBlock";
import {StageContext} from "../../context";
import {Layer, Rect, Stage} from "react-konva";

function App() {
    const [stage, setStage] = useState(
        <Stage width={500} height={500}>
            <Layer>
                <Rect width={500} height={500} />
            </Layer>
        </Stage>
    );

    return (
        <StageContext.Provider value={stage}>
            <LeftBlock />
            <ControlBlock />
        </StageContext.Provider>
    );
}

export default App;

Вот сам контекст

import {createContext} from 'react';

export const StageContext = createContext(null);

И вот сама сцена в левом блоке

const KonvaStage = () => {
    const stage = useContext(StageContext);
    return (
        {stage}
    );
};

В этом случае, в консоли пишет: Uncaught Error: Objects are not valid as a React child (found: object with keys {Stage}). If you meant to render a collection of children, use an array instead.

Что я не так делаю и как настроить взаимодействие между кнопкой и прямоугольником на сцене?


Ответы (1 шт):

Автор решения: EzioMercer

Объясню принцип работы основной логики:

  • Объявляем контекст const ColorContext = createContext()
  • Оборачиваем элементы, которые будут использовать этот контекст в тег ColorContext.Provider
  • Объявляем значение как объект, в котором 1 поле для значения цвета и 1 метод для обновления цвета value={{color, setColor}}
  • В любых дочерних компонентах достаём поле или метод в зависимости от того, кому что надо. Например кнопке не важно знать, какой сейчас цвет, его дело - просто назначить нужный цвет, потому он использует только метод обновления цвета const {setColor} = useContext(ColorContext). Самому блоку же, плевать кто и как обновлят цвет, ему важно знать только нынешний цвет, потому использует только поле, где значение цвета const {color} = useContext(ColorContext)

Код:

const {useState, useContext, createContext} = React;

const ColorContext = createContext();

const Button = ({text, changeValue}) => {
  const {setColor} = useContext(ColorContext);
  
  return (
    <button onClick={() => setColor(changeValue)}>{text}</button>
  )
}

const ButtonsBlock = () => {  
  return (
    <React.Fragment>
      <Button text={'Red'} changeValue={'red'} />
      <Button text={'Green'} changeValue={'green'} />
      <Button text={'Blue'} changeValue={'blue'} />
    </React.Fragment>
  )
}

const Block = () => {  
  const {color} = useContext(ColorContext);
  
  return (
    <div className='block' style={{border: `2px solid ${color}`}}></div>
  )
}

const App = () => {
  const [color, setColor] = useState('red');
  
  return (
    <ColorContext.Provider  value={{color, setColor}}>
      <Block />
      <ButtonsBlock />
    </ColorContext.Provider>
  )
};

ReactDOM.render(
  <App />,
  document.getElementById('root')
)
body {
  background-color: #777;
}

.block {
  width: 50px;
  height: 50px;
  margin-bottom: 8px;
}
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.production.min.js"></script>

→ Ссылка