skip to Main Content

I am trying to add a button component to my project and include children within it when rendering JSX, I want the button to change color once it is clicked. I have three files in my project that return a different result in the DOM, I would like these JSX.Element functions to be passed into them so it can be used in each component without repeating myself in each of the component files.

I tried creating a Button function, code below:

Button.tsx

import { useState } from "react";

export function Button() {
  const [color, setColor] = useState("pink");
  const [textColor, setTextColor] = useState("green");
  return (
    <button
      style={{ background: color, color: textColor }}
      className="statusButton"
      onClick={() => {
        setColor("pink");
        setTextColor("green");
      }}
    ></button>
  );
}

Active component that I am trying to pass Button into:

Active.tsx

import { Button } from "./Button"

export const ActiveTasks = (props: {
// passing props to JSX components
  newTask: () => void;
  toDos: ToDo[];
  showAllTasks: () => void;
  showDone: () => void;
  setToDos: (value: React.SetStateAction<ToDo[]>) => void;
}) => {

return(
// Left out code in rest of App, below is where I want to pass in the Button function and include children.
 <div className="status-container">
// 
          <Button
            id="allButton"
            className="statusButton"
            onClick={props.showAllTasks}
          >
            All

          </Button>
);
}

When I tried this in my project I got the following error:
TS2322: Type ‘{ children: string; id: string; className: string; onClick: () => void; }’ is not assignable to type ‘IntrinsicAttributes’.
Property ‘children’ does not exist on type ‘IntrinsicAttributes’.

I added the Button function by itself inside of the status-container div, example below:

<div className="status-container">
          <button
            id="allButton"
            className="statusButton"
            onClick={props.showAllTasks}
          >
            <Button />
            All
         </button>

Just to see if the code worked. As expected, it returned an additional button, I just want the changes above made only to my "statusButton" How can I go about doing this?

2

Answers


  1. To send a child you need define props,
    you can try this,

    type ButtonProps = PropsWithChildren<{}>
    

    and then use the same in,

    export function Button(props :ButtonProps) {
    

    Now refer, props.children in the next part of your code.

    To summarize,

    import { useState } from "react";
    type ButtonProps = PropsWithChildren<{}>
    export function Button(props :ButtonProps) {
      const [color, setColor] = useState("pink");
      const [textColor, setTextColor] = useState("green");
      return (
        <button
          style={{ background: color, color: textColor }}
          className="btn btn-primary"
          onClick={() => {
            setColor("pink");
            setTextColor("green");
          }}
        >{props.children}</button>
      );
    }
    

    This should solve your issue. Improving this code further, I would suggest you define a props that would extend props from HTML Button so, that you will still be able to get all HTML defined props along with your custom props, Enhanced code would be this,

    type ButtonProps = React.HTMLProps<HTMLButtonElement>
    export function Button(props :ButtonProps) {
      const [color, setColor] = useState("pink");
      const [textColor, setTextColor] = useState("green");
      return (
        <button
          {...props}
          style={{ background: color, color: textColor, ...(props && props.style) }}
          className=`btn btn-primary + ${props.className ? props.className: ''}`
          onClick={(e) => {
            setColor("pink");
            setTextColor("green");
            props.onClick ?? props.onClick(e);
          }}
        />
      );
    }
    
    Login or Signup to reply.
  2. This is a simple Typescript error; you’re not defining that the Button component can accept children.

    Just modify the Button component definition to look like this:

    export const Button: React.FC = ({ children }) => {
    

    And of course use the children prop.

    Full version:

    export const Button: React.FC = ({ children }) => {
      const [color, setColor] = useState("pink");
      const [textColor, setTextColor] = useState("green");
      return (
        <button
          style={{ background: color, color: textColor }}
          className="btn btn-primary"
          onClick={() => {
            setColor("pink");
            setTextColor("green");
          }}
        >
          {children}
        </button>
      );
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search