Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use functional component instead of class-based for template MyComponent #100

Merged
merged 5 commits into from
Dec 4, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 42 additions & 59 deletions template/my_component/frontend/src/MyComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,84 +1,67 @@
import {
Streamlit,
StreamlitComponentBase,
withStreamlitConnection,
ComponentProps,
} from "streamlit-component-lib"
import React, { ReactNode } from "react"

interface State {
numClicks: number
isFocused: boolean
}
import React, { useEffect, useState, ReactElement } from "react"

/**
* This is a React-based component template. The `render()` function is called
sfc-gh-bnisco marked this conversation as resolved.
Show resolved Hide resolved
* automatically when your component should be re-rendered.
*/
class MyComponent extends StreamlitComponentBase<State> {
public state = { numClicks: 0, isFocused: false }
function MyComponent({ args, disabled, theme }: ComponentProps): ReactElement {
const { name } = args

public render = (): ReactNode => {
// Arguments that are passed to the plugin in Python are accessible
// via `this.props.args`. Here, we access the "name" arg.
const name = this.props.args["name"]
const [isFocused, setIsFocused] = useState(false)
const [style, setStyle] = useState<React.CSSProperties>({})
const [numClicks, setNumClicks] = useState(0)

// Streamlit sends us a theme object via props that we can use to ensure
// that our component has visuals that match the active theme in a
// streamlit app.
const { theme } = this.props
const style: React.CSSProperties = {}
useEffect(() => {
if (!theme) return

// Maintain compatibility with older versions of Streamlit that don't send
// a theme object.
if (theme) {
// Use the theme object to style our button border. Alternatively, the
// theme style is defined in CSS vars.
const borderStyling = `1px solid ${
this.state.isFocused ? theme.primaryColor : "gray"
}`
style.border = borderStyling
style.outline = borderStyling
}
// Use the theme object to style our button border. Alternatively, the
// theme style is defined in CSS vars.
const borderStyling = `1px solid ${isFocused ? theme.primaryColor : "gray"}`
setStyle({ border: borderStyling, outline: borderStyling })
}, [theme, isFocused])
sfc-gh-bnisco marked this conversation as resolved.
Show resolved Hide resolved

// Show a button and some text.
// When the button is clicked, we'll increment our "numClicks" state
// variable, and send its new value back to Streamlit, where it'll
// be available to the Python program.
return (
<span>
Hello, {name}! &nbsp;
<button
style={style}
onClick={this.onClicked}
disabled={this.props.disabled}
onFocus={this._onFocus}
onBlur={this._onBlur}
>
Click Me!
</button>
</span>
)
}
useEffect(() => {
Streamlit.setComponentValue(numClicks)
}, [numClicks])

/** Click handler for our "Click Me!" button. */
private onClicked = (): void => {
// Increment state.numClicks, and pass the new value back to
// Streamlit via `Streamlit.setComponentValue`.
this.setState(
prevState => ({ numClicks: prevState.numClicks + 1 }),
() => Streamlit.setComponentValue(this.state.numClicks)
)
const onClicked = (): void => {
setNumClicks((prevNumClicks) => prevNumClicks + 1)
}

/** Focus handler for our "Click Me!" button. */
private _onFocus = (): void => {
this.setState({ isFocused: true })
const onFocus = (): void => {
setIsFocused(true)
}

/** Blur handler for our "Click Me!" button. */
private _onBlur = (): void => {
this.setState({ isFocused: false })
const onBlur = (): void => {
setIsFocused(false)
}
sfc-gh-bnisco marked this conversation as resolved.
Show resolved Hide resolved

// Show a button and some text.
// When the button is clicked, we'll increment our "numClicks" state
// variable, and send its new value back to Streamlit, where it'll
// be available to the Python program.
return (
<span>
Hello, {name}! &nbsp;
<button
style={style}
onClick={onClicked}
disabled={disabled}
onFocus={onFocus}
onBlur={onBlur}
>
Click Me!
</button>
</span>
)
}

// "withStreamlitConnection" is a wrapper function. It bootstraps the
Expand Down
Loading