6

I am creating a small web app in reactjs template provided by visual studio 2017. I am stuck in a situation where i want a function to be passed as a state to a child component and then invoke that function through child component. I have a header component where i have a method called setLogInTrue() which i want to pass to my SignIn component. Below is my code:-

Header.tsx

class HeaderState {
isLoggedIn: boolean;
}

export class Header extends React.Component<HeaderProps, HeaderState> {
constructor() {
    super()
    this.state = ({ isLoggedIn: false });
    this.setLogInTrue= this.setLogInTrue.bind(this);
}

setLogInTrue() {
    this.setState({ isLoggedIn: true });
}

public render(){
//Some elements
<NavLink className="link header_row_link" to={{ pathname: '/signIn', state: this.setLogInTrue }}> //<-- i thought this would work and give the function in the location of SignIn components state but it does not.
              Sign In
</NavLink>
  }
}

SignIn.tsx

export class SignIn extends React.Component<RouteComponentProps<{}>, {}>  {

constructor() {
    super();
}

public render() {
    return <div className="signin_wrapper">
        <SignInContent />
    </div>;
  }
}

I want to access that function here and pass it to SignInContent component, and then invoke that function from there.

This code does not give me any compile time errors but whenever i click on the sign in link it gives me the following error

Uncaught DOMException: Failed to execute 'pushState' on 'History': function () { [native code] } could not be cloned.

i tried this solution but it does not work for me. It still gives me this error or gives state as undefined. I am very new to react and any help would be appreciated

Prasaad Patil
  • 447
  • 3
  • 6
  • 20
  • 2
    From [MDN](https://developer.mozilla.org/en-US/docs/Web/API/History_API#The_pushState()_method): _"`pushState()` takes three parameters: a **state** object, a title, and a URL."_ -> _"The state object can be anything that can be **serialized**"_ -> _"Starting in Gecko 6.0 (Firefox 6.0 ...), the object is serialized using the **structured clone algorithm**."_ -> _"Things that **don't work** with structured clone: `Error` and **`Function` objects** cannot be duplicated by the structured clone algorithm; attempting to do so **will throw a DATA_CLONE_ERR exception**."_ – Andreas May 31 '18 at 06:53
  • If the function is not allowed then is there an alternate way to do so? – Prasaad Patil May 31 '18 at 06:57

3 Answers3

5

This error occurs, as @Andreas mentioned in a comment, when DOM elements or anything non-serializable is used in the state object which is being assigned to window.history.state via history.replaceState or history.pushState. For example try: history.pushState({node: document.body}, 'title', '#/error') or use {node: History} instead and it will produce a similar DOMException error. To fix it simply remove the problematic objects or in some way be more deliberate about what is being pushed into the state.

jimmont
  • 2,304
  • 1
  • 27
  • 29
5

I had the same issue when the React component state contained non serialized objects.

I just needed to stringify the whole React state object before pushing it to the browser's history state like this:

window.history.pushState(JSON.stringify(state), "", getSecuredURL(url));
Ahmed Daraz
  • 81
  • 1
  • 3
2

I also had the same issue with pushing a React component state that contained functions. I didn't want to call JSON.strinfigy though because it can contain dates and those don't stringify/parse well. Instead, I chose to do:

window.history.pushState(cleanStateForHistory(state), "", someURL);

/**
 * Remove the functions from the state. They can't been pushed into the history.
 */
export function cleanStateForHistory(state) {
  const stateWithNoFunctions = {};
  for (const key of Object.keys(state)) {
    if (typeof key !== "function") {
      stateWithNoFunctions[key] = state[key];
    }
  }
  return stateWithNoFunctions;
}

Ryan Shillington
  • 23,006
  • 14
  • 93
  • 108