0

As the title says, I want to change value of props and reload component in external js file.

<div data-group=""></div>
//external.js
const popupChat = document.getElementById('popupChatComponent');
popupChat.setAttribute('data-group', groupId);
//component.ts
export default class PopupChatRoot extends React.Component {
    private readonly groupId: string;

    constructor(props) {
        super(props);
        this.groupId = this.props.group;
    }

    render() {
        return (
            <div className="modal-body">
                <p>{this.groupId}</p>
            </div>
        );
    }
}

const component = document.getElementById('popupChatComponent');
if (component) {
    const props = Object.assign({}, component!.dataset);
    render(<PopupChatRoot {...props}/>, component);
}

How I can do this ?

frenchqwerty
  • 97
  • 1
  • 14
  • I don't think you can update the props. see this, https://stackoverflow.com/questions/24939623/can-i-update-a-components-props-in-react-js – will92 Mar 04 '19 at 23:34

2 Answers2

2

What you can do is use a wrapper component or higher order component which provides those props to your component, and have that have that wrapper component integrated with your external javascript code.

Here is an HOC I use to do something similar:

export interface MyHocProps {
    //the props you want to provide to your component
    myProp: any;
}

export const withMyHOC = <T extends any>(params: any) =>

<P extends MyHocProps>(WrappedComponent: React.ComponentType<P>): React.ComponentClass<defs.Omit<P, keyof MyHocProps>> => {

    return class extends React.PureComponent<defs.Omit<P, keyof MyHocProps>> {

        //here you have access to params, which can contain anything you want
        // maybe you can provide some sort of observable which causes this to re-render

        render() {

            return <WrappedComponent
                {...this.props}
                myProp={/*whatever*/}
            />;
        }
    }
};

From here, you would integrate this HOC with some kind of system to push changes to it. I recommend using an observable. Basically you want to have this HOC component subscribe to changes in some piece of observable data, and then force itself to re-render when it changes.

Alternatively, you can just expose some method on your component if it is just a singleton by doing something like window.reloadThisComponent = this.reload.bind(this);, but that should probably be considered a last resort.

Matt H
  • 1,795
  • 1
  • 7
  • 8
  • Using an HOC is surely better way to do this than my answer. Merge my answer with this one can help you solve your issue. – Alexandre Nicolas Mar 05 '19 at 00:03
  • I have a question, `defs` is not recognized by typescript and `this.props` too. – frenchqwerty Mar 05 '19 at 16:10
  • I'm not understand. – frenchqwerty Mar 05 '19 at 20:34
  • 1
    defs.Omit is a custom type I use to remove keys from an interface. It is implemented as `type Omit = Pick>`. I use it to indicate to the parent component that it doesn't need to prove that property since it is being provided by the HOC. `this.props` should be recognized, not sure what is going on there. – Matt H Mar 06 '19 at 02:07
0

It is just a generic example, it might help you to solve your problem. Actually I don't think you can change props of the root node.

// yourEventService.js
class YourEventService {

  listeners = []

  subscribe = listener => this.listeners.push(listener)

  unsubscribe = listener => this.listeners = this.listeners.filter(item => item !== listener)

  emit = message => listener.forEach(listener => listener(message))

}

export default new YourEventService() // singleton export
// someWhereElse.js

import yourEventService from './yourEventService'

window.addEventListener('click', () => yourEventService.emit('myNewGroup')) // it's just an event example

//component.js, sorry I don't know how to typescript well
import yourEventService from './yourEventService'

export default class PopupChatRoot extends React.Component {

    state = {
        groupId: this.props.group; // initial value is passed by props
    }


    componentDidMount() {
        yourEventService.subscribe(this.handleMessage)
    }

    componentWillUnmount() {
        yourEventService.unsubscribe(this.handleMessage)
    }

    handleMessage = message => {
        this.setState({ groupId: message })
    }

    render() {
        return (
            <div className="modal-body">
                <p>{this.state.groupId}</p>
            </div>
        );
    }
}

const component = document.getElementById('popupChatComponent');
if (component) {
    const props = Object.assign({}, component.dataset);
    render(<PopupChatRoot {...props}/>, component);
}
Alexandre Nicolas
  • 1,851
  • 17
  • 19