How to call setProps of a child component?

I would like to be able to edit some component properties of child components. Say for example that I want to create a wrapper component Wrapper that changes the value of some_prop to some_value of its child component (let’s assume that there is one and only one child for simplicity). I can do the edit itself like this,

const Wrapper = ({children}) => {
    children.props._dashprivate_layout.props.some_prop = "some_value"
    return <Fragment>{children}</Fragment>;
}

I have confirmed that it works if i read the value of some_prop from a callback in Dash. However, the value change does not cause a callback invocation.

I believe that what I essentially need to do is call setProps on the child object to invoke the callback - but is that possible at all? How could I do that? Maybe @chriddyp or @alexcjohnson knows?

Any ideas are welcome :slight_smile:

1 Like

Very interesting @Emil - can you say a bit more about your use case?

What you’re seeing there as children is one or more <TreeContainer> elements, which are wrappers around wrappers around the actual Dash components. So it’s pretty tricky to imagine digging into that to find the right setProps method, and it’s setProps that ultimately needs to be called to invoke callbacks.

So unless you can find a way to do that, I think we’d need an update to the renderer to support this. One option that occurs to me is to allow an optional second arg to setProps which is a path (within the current component’s layout) to the component you want to edit. In the case of a single component not wrapped in an array this would look like ['children', 'props'], if there is an array ['children', 0, 'props'], but more complicated deeper nestings would also be possible ['children', 3, 'props', 'children', 'props', 'children', 5, 'props'] etc etc.

Of course it’s far from clear how you’d go about constructing the appropriate path, but I guess in principle all the info you need to crawl children and figure that out is available in children.props._dashprivate_layout, or children[i].props._dashprivate_layout if children is an array.

2 Likes

Thank you for the interest @alexcjohnson . My current use case is a ListOperator component that performs list operations (append, clear, …). It could be on a Store component for example,

app = Dash()
app.layout = html.Div([
    html.Button("Click me", id="btn"),
    ListOperator(dcc.Store(data=[], id="store"), prop="data", id="operator"),
])

The idea would then be to enable list operations via callbacks,

@app.callback(Output("operator", "apply"), Input("btn", "n_clicks"))
def add_data(n_clicks):
    if not n_clicks:
        return dash.no_update
    uid = str(datetime.now().timestamp())  # unique id
    return dict(operation="append", value=n_clicks, id=uid)

which would append the n_clicks value to the list inside the Store component. The syntax is not settled, but I guess the above pseudo code illustrates the basic idea. I imagine the same kind of approach could be used for dictionary operations.

With regards to the setProps function, I am currently stuck not being able to locate it at all. If I print the children object to console,

I do see the _dash_private_layout, which contains user input props, but not the setProps function. I guess that’s because setProps is injected by the renderer at a later point? I also tried passing a reference via the ref property when I render the Fragment,

const ListOperator = ({children}) => {
    const myRef = React.createRef()

    useEffect(() => {
        console.log(children)
    });

    return <Fragment ref={myRef}>{children}</Fragment>;
}

but what i get in the console is just null. I guess that’s because the output of the render function of Store is null. So that didn’t help much either :laughing:

I’m also interested in how this could be achieved - I have a similar use case, and have resorted to horrible hacks that end up force re-rendering all children with transmogrified props, which is less than ideal.

Hi,

I’m facing the very same issue trying to build a custom component that sync prop of children across multiple users using WebSocket. Do we have any update concerning this ?

By digging a bit into the code, I saw that component have a path has described in the reply by @alexcjohnson , but does the setProps function support this ? Didn’t find any info about it…

This functionality would open a lot of room to build custom component that wrap around already existing component.